How to Implement iOS library Animation: Part 1 (Part 2)

Source: Internet
Author: User

How to Implement iOS library Animation: Part 1 (Part 2)

Link to the original article: How to Create an iOS Book Open Animation: Part 1 Author: Vincent Ngo translated from: Development Technology frontline www.devtf.cn Translator: kmyhy
Page flip Layout

The final result is as follows:

It looks like a real book! :]

Create a new Layout folder in the Book folder. Right-click the Layout folder and choose New File ..., Next, apply the iOSSourceCocoa Touch Class template, and click Next. The class name is BookLayout, inherited from UICollectionViewFlowLayout, and the language is Swift.

As before, the Collection View used by books must apply to the new layout. Open Main. storyboard, select the Book View Controller scenario, expand and select the Collection View, and set the Layout attribute to Custom.

Then, set the Class attribute under the Layout attribute to BookLayout:

Open BookLayout. swift and add the following code to the class declaration:

private let PageWidth: CGFloat = 362private let PageHeight: CGFloat = 568private var numberOfItems = 0

These constants are used to set the cell size and record the number of pages in the entire book.
Then, add the code inside the class declaration:

override func prepareLayout() {  super.prepareLayout()  collectionView?.decelerationRate = UIScrollViewDecelerationRateFast  numberOfItems = collectionView!.numberOfItemsInSection(0)  collectionView?.pagingEnabled = true}

This code is similar to what we wrote in BooksLayout, with only the following differences:

Set the deceleration speed to UIScrollViewDecelerationRateFast to accelerate the scrolling speed of the Scroll View. Remember the number of pages in the book. Enable paging, so that Scroll View will Scroll with a fixed multiple of its width (rather than rolling continuously ).

Add the following code to BookLayout. swift:

override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {  return true}

Returns true, as in the previous step, indicating that the layout is recalculated every time the user scrolls.

Then, overwrite collectionViewContentSize () to specify the contentSize of the Collection View:

override func collectionViewContentSize() -> CGSize {  return CGSizeMake((CGFloat(numberOfItems / 2)) * collectionView!.bounds.width, collectionView!.bounds.height)}

This method returns the entire size of the content area. The height of the content area is always the same, but the width changes with the number of pages-that is, the number of pages of a book is divided by two times, and then multiplied by the screen width. Divide by 2 because there are two sides to the book page. The content area displays two pages at a time.

Just as we did in BooksLayout, we also need to overwrite the layoutAttributesForElementsInRect (_ :) method so that we can add page flip effects on cells.

Add the following content after the collectionViewContentSize () method:

override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {  //1  var array: [UICollectionViewLayoutAttributes] = []  //2  for i in 0 ... max(0, numberOfItems - 1) {    //3    var indexPath = NSIndexPath(forItem: i, inSection: 0)    //4    var attributes = layoutAttributesForItemAtIndexPath(indexPath)    if attributes != nil {      //5      array += [attributes]    }  }  //6  return array}

Unlike in BooksLayout, we put all the code for calculating the layout attribute in this method. This task is put in layoutAttributesForItemAtIndexPath (_ :), because in the implementation of books, all cells are visible at the same time.

The above code is explained as follows:

Declare an array to save the layout attributes of all cells. Traverse all book pages. Create an NSIndexPath for each cell in CollecitonView. Use each NSIndexPath to obtain the layout attribute of a cell. Later, we will overwrite the layoutAttributesForItemAtIndexPath (_ :) method. Add the layout attribute of each cell to the array. Returns an array. Process page geometric Computation

Before we begin to implement the layoutAttributesForItemAtIndexPath (_ :) method, let's take a few minutes to think about how the layout is implemented, if we can write several helper methods, it will make our code more beautiful and modular. :]

Demonstrate the process of turning pages with books as the axis. In the figure, the opening degree is represented by-1 to 1. Why? You can imagine a book on the table where the spine is 0.0. When you flip a page from left to right, the page opens from-1 (leftmost) to 1 (rightmost ). Therefore, we can use the following numbers to represent the process of turning pages:

0.0 indicates that a book page turns to 90 degrees, at a right angle to the desktop. +/-0.5 indicates that the book page is converted to a 45-degree angle on the desktop. +/-1.0 indicates that the book page is displayed parallel to the desktop.

Note that because the angle is increased in the opposite direction, the angle symbol is opposite to the open degree.

First, add the Helper method after the layoutAttributesForElementsInRect (_ :) method:

//MARK: - Attribute Logic Helpersfunc getFrame(collectionView: UICollectionView) -> CGRect {  var frame = CGRect()  frame.origin.x = (collectionView.bounds.width / 2) - (PageWidth / 2) + collectionView.contentOffset.x  frame.origin.y = (collectionViewContentSize().height - PageHeight) / 2  frame.size.width = PageWidth  frame.size.height = PageHeight  return frame}

For each page, we can calculate the frame relative to the center of the Collection View. The getFrame (_ :) method will align one side of each page to the spine. The only change is the change in the contentOffset of Collectoin View in the x direction.

Then, add the following method after the getFrame (_ :) method:

func getRatio(collectionView: UICollectionView, indexPath: NSIndexPath) -> CGFloat {  //1  let page = CGFloat(indexPath.item - indexPath.item % 2) * 0.5  //2  var ratio: CGFloat = -0.5 + page - (collectionView.contentOffset.x / collectionView.bounds.width)  //3  if ratio > 0.5 {    ratio = 0.5 + 0.1 * (ratio - 0.5)  } else if ratio < -0.5 {    ratio = -0.5 + 0.1 * (ratio + 0.5)  }  return ratio}

The above method calculates the page opening degree. The annotated code for each section is described as follows:

Calculate the page number-remember, the book is double-sided. Divided by 2 is the page you are actually reading. Calculate the page opening degree. Note that we add a weight to this value. The page must be opened between-0.5 and 0.5. In addition, the function of multiplying by 0.1 is to add a slit between pages to indicate that they are stacked up and down.

Once we calculate the open degree of a publishing page, we can turn it into a rotation angle.
Add the code after the getRation (_: indexPath :) method:

func getAngle(indexPath: NSIndexPath, ratio: CGFloat) -> CGFloat {  // Set rotation  var angle: CGFloat = 0  //1  if indexPath.item % 2 == 0 {    // The book's spine is on the left of the page    angle = (1-ratio) * CGFloat(-M_PI_2)  } else {    //2    // The book's spine is on the right of the page    angle = (1 + ratio) * CGFloat(M_PI_2)  }  //3  // Make sure the odd and even page don't have the exact same angle  angle += CGFloat(indexPath.row % 2) / 1000  //4  return angle}

There is a lot of computing in this method. Let's take a look at it a little bit:

Determines whether the page is an even page. If yes, the page will jump to the right of the spine. Turning to the right page is a backhand flip, and the angle of the page on the right of the spine must be a negative number. Note: We define the degree of enable as-0.5 to 0.5. If the current page is an odd number, the page is on the left of the spine. When the page is turned to the left, it is flipped by the front hand, and the angle of the page on the left of the spine is positive. Each page is separated by a small angle. Returns the rotation angle.

After obtaining the rotation angle, we can manipulate the book page to make it rotate. Add the following method:

func makePerspectiveTransform() -> CATransform3D {  var transform = CATransform3DIdentity  transform.m34 = 1.0 / -2000  return transform}

Modifying the m34 attribute of the conversion matrix has achieved a certain level of stereoscopic effect.
Then apply the rotation animation. The following method is implemented:

func getRotation(indexPath: NSIndexPath, ratio: CGFloat) -> CATransform3D {  var transform = makePerspectiveTransform()  var angle = getAngle(indexPath, ratio: ratio)  transform = CATransform3DRotate(transform, angle, 0, 1, 0)  return transform}

In this method, we used the two Assistant methods just created to calculate the rotation angle, and then rotated the book page on the Y axis through a CATransform3D object.

All helper methods are implemented, and we finally need to configure the attributes of each cell. Add the following method after the layoutAttributesForElementsInRect (_ :) method:

override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {  //1  var layoutAttributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)  //2  var frame = getFrame(collectionView!)  layoutAttributes.frame = frame  //3  var ratio = getRatio(collectionView!, indexPath: indexPath)  //4  if ratio > 0 && indexPath.item % 2 == 1     || ratio < 0 && indexPath.item % 2 == 0 {    // Make sure the cover is always visible    if indexPath.row != 0 {      return nil    }  }   //5  var rotation = getRotation(indexPath, ratio: min(max(ratio, -1), 1))  layoutAttributes.transform3D = rotation  //6  if indexPath.row == 0 {    layoutAttributes.zIndex = Int.max  }  return layoutAttributes}

This method is called on every cell in the Collection View. This method does the following:

Create a UICollectionViewLayoutAttributes object named layoutAttributes for the cells indicated by IndexPath. Call the previously defined getFrame method to set the layoutAttributes frame to ensure that the cell is aligned with the spine. Call the previously defined getRatio method to calculate the open degree of a cell. Determines whether the current page is within the correct open range. If no, this cell is not displayed. In order to optimize (and to comply with common sense), we should not display the back of the book page, except the cover of the book, which should be displayed at any time. Apply the rotation animation and use the previously calculated opening degree. Determine whether it is the first page. If yes, place its zIndex on the top of other pages. Otherwise, the screen may flash.

Compile and run. Open a book, flip every page ...... Er? What is the situation?

The book was mistakenly bound from the middle, rather than from the side of the book.

As shown in, the anchor of each book page is 0.5 times the X axis and Y axis by default. Do you know how to do it now?

Obviously, we need to modify the anchor of the book page as its side edge. If the page is on the right side of the book, its anchor should be (0, 0.5 ). If the book page is on the left of the book, the test anchor should be (1, 0.5 ).

Open BookePageCell. swift and add the following code:

override func applyLayoutAttributes(layoutAttributes: UICollectionViewLayoutAttributes!) {  super.applyLayoutAttributes(layoutAttributes)  //1  if layoutAttributes.indexPath.item % 2 == 0 {    //2    layer.anchorPoint = CGPointMake(0, 0.5)    isRightPage = true    } else { //3      //4      layer.anchorPoint = CGPointMake(1, 0.5)      isRightPage = false    }    //5    self.updateShadowLayer()}

We have rewritten the applyLayoutAttributes (_ :) method, which is used to apply the layout attribute created by BookLoayout to the first one.
The above code is very simple:

Check whether the current cell is an even number, that is, whether the spine is on the left of the page. If yes, set the anchor of the book page to the left edge of the cell, and set isRightPage to true. The isRightPage variable can be used to determine which corner styles of the book page should be applied on that side. If it is an odd page, the spine should be on the right of the page. The anchor of this book page is the right edge of the cell, and isRightPage is set to false. Finally, set the shadow layer of the current book page.

Compile and run. The effect of this time is much better when you flip the pages:

The first part of this tutorial ends here. Do you think you have done something amazing-the effect is doing great, isn't it?

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.