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

Source: Internet
Author: User

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

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

This tutorial consists of two parts:

In part 2, you will learn how to customize Collection View Layout and make the App look more authentic by using depth and shadow.

In part 2, you will learn how to create custom transition effects between two different controllers in a reasonable way, and use gestures to create a natural and intuitive transition between the two views.

This tutorial applies to intermediate-advanced developers. You will use custom transition animations and custom Collection View Layout. If you have never used Colleciton View, please refer to other iOS tutorials first.

Note: Thanks to Attila Hegd üs for creating the sample project in this tutorial.

Start

Download the START project of this tutorial. Unzip the zip package and use Xcode to open Paper. xcodeproj.

Compile the project and run the App in the simulator. You will see the following picture:

The function of this App has been improved. you can scroll through your library, view books, and select a book to browse. But when you read a book, why are its pages placed side by side? With some knowledge of UICollectionView, you can make these pages look better!

Project Structure

Here's a quick rundown of the most important bits of the starter project:

There are several important points to explain about this project:

The Data Models folder contains three files:

Books. plist contains several Books for demonstration. Each book contains a cover image and an array of images that represent the content of each page. BookStore. swift implements a singleton. Only one object can be created during the entire App declaration cycle. BookStore is responsible for loading data from Books. plist and creating Book-class instances. Book. swift is used to store the Book-related information, such as the album art, pictures on each page, and page number.

The Books folder contains two files:

BooksViewController. swift is a subclass of UICollectionViewController. Lists books in horizontal mode. BookCoverCell. swift is responsible for displaying the album art of a book. This class is referenced by the BooksViewController class.

In the Book folder, it includes:

BookViewController. swift is also a subclass of UICollectionViewController. After you select a book in BooksViewController, it displays the book pages in the book. BookPageCell. swift is used by BookViewController to display book pages in books.

The last folder Helper contains:

UIImage + Helpers. swift is an extension of UIImage. This extension contains two practical methods: one for displaying an image with rounded corners and the other for scaling the image to a specified size.

This is the general introduction of the entire start Project-it's time for us to write some code!

Customized library interface

First, we need to overwrite the default layout of Collection View in BooksViewController. However, the current layout is to display three large pictures on the screen. For the sake of appearance, we can reduce these images to a certain size, as shown in:

When we move the image to the center of the screen, the image will be enlarged to indicate that the book is selected. If you continue to slide, the cover of the book will be reduced to one side, indicating that we will not choose the book.

Create a folder group named Layout in the AppBooks folder. Right-click Layout and choose New File ..., Select the iOSSourceCocoa Touch Class template and click Next. The class name is BooksLayout, inherits the UICollectionViewFlowLayout class, and the language is set to Swift.

Then we need to tell the Collection View in BooksViewController that the newly created BooksLayout is applicable.

Open Main. storyboard, expand the BooksViewController object, and select Collection View. On the attribute panel, set the Layout attribute to Custom and the Class attribute to BooksLayout, as shown in:

Open BooksLayout. swift and add the following code on the BooksLayout class declaration:

private let PageWidth: CGFloat = 362private let PageHeight: CGFloat = 568

The two constants are used to set the cell size.
The following initialization method is defined within the class definition:

required init(coder aDecoder: NSCoder) {  super.init(coder: aDecoder)  scrollDirection = UICollectionViewScrollDirection.Horizontal //1  itemSize = CGSizeMake(PageWidth, PageHeight) //2  minimumInteritemSpacing = 10 //3}

The above code serves the following purposes:

Set the scroll direction of the Collectioin View to the horizontal direction. Set the size of a cell to PageWidth and PageHeight, that is, 362x568. Set the spacing between two cells to 10.

Then, add the code to the init (coder :) method:

override func prepareLayout() {  super.prepareLayout()  //The rate at which we scroll the collection view.  //1  collectionView?.decelerationRate = UIScrollViewDecelerationRateFast  //2  collectionView?.contentInset = UIEdgeInsets(    top: 0,    left: collectionView!.bounds.width / 2 - PageWidth / 2,    bottom: 0,    right: collectionView!.bounds.width / 2 - PageWidth / 2  )}

The prepareLayout () method allows us to perform some calculations before the layout information of each cell takes effect.

Corresponding to the number in the comment, the above Code is described as follows:

Set Collection when the user's finger leaves
The speed at which the View stops scrolling. The default setting is UIScrollViewDecelerationRateFast, which is a fast speed. You can try to set it to Normal and Fast to see what is the difference between them. Set the contentInset of the Collection View so that the cover of the first book is located in the center of the Collection View.

Now we need to process the layout information of each cell.
Add the following code under the prepareLayout () method:

override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {  //1  var array = super.layoutAttributesForElementsInRect(rect) as! [UICollectionViewLayoutAttributes]  //2  for attributes in array {    //3    var frame = attributes.frame    //4    var distance = abs(collectionView!.contentOffset.x + collectionView!.contentInset.left - frame.origin.x)    //5    var scale = 0.7 * min(max(1 - distance / (collectionView!.bounds.width), 0.75), 1)    //6    attributes.transform = CGAffineTransformMakeScale(scale, scale)  }  return array}

The layoutAttributesForElementsInRect (_ :) method returns an array of UICollectionViewLayoutAttributes objects, which contains the layout attributes of each cell. The above code is described as follows:

Call the layoutAttributesForElementsInRect method of the parent class to obtain the default Cell Layout attribute. Traverse the layout attributes of each cell in the array. Read the frame from the Cell Layout attribute. Calculate the gap between the covers of the two books-that is, the gap between two cells-and the center of the screen. Take 0.75 ~ The ratio between 1 and the cover is scaled. The specific ratio depends on the distance calculated above. Then all the covers are scaled to 70% for the sake of beauty. Finally, apply the affine transform.

Next, add the following code after the layoutAttributesForElementsInRect (_ :) method:

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

If the return value is true, the layout attribute is forcibly recalculated whenever the bounds of the Collection View changes. The Collection View will change its bounds when scrolling, so we need to recalculate the layout attribute of the cell.

Compile and run the program. We will see that the cover in the center is significantly larger than other covers:

Drag Colleciton View to zoom in and out each book. But there is still a slight deficiency. Why not let the books be stuck in a fixed position?
Next we will introduce this method.

Align books

The targetContentOffsetForProposedContentOffset (_: withScrollingVelocity :) method is used to calculate the position to which each book should be aligned. It returns an offset and can be used to set the contentOffset of the Collection View. If you do not overwrite this method, it returns a default value.

Add the following code after the shouldInvalidateLayoutForBoundsChange (_ :) method:

override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {  // Snap cells to centre  //1  var newOffset = CGPoint()  //2  var layout = collectionView!.collectionViewLayout as! UICollectionViewFlowLayout  //3  var width = layout.itemSize.width + layout.minimumLineSpacing  //4  var offset = proposedContentOffset.x + collectionView!.contentInset.left  //5  if velocity.x > 0 {    //ceil returns next biggest number    offset = width * ceil(offset / width)  } else if velocity.x == 0 { //6    //rounds the argument    offset = width * round(offset / width)  } else if velocity.x < 0 { //7    //removes decimal part of argument    offset = width * floor(offset / width)  }  //8  newOffset.x = offset - collectionView!.contentInset.left  newOffset.y = proposedContentOffset.y //y will always be the same...  return newOffset}

This Code calculates the offset of the cover when the user's finger leaves the screen:

Declare a CGPoint. Obtain the current layout of the Collection View. Obtains the total width of a cell. Calculate the currentOffset relative to the center of the screen. If velocity. x> 0, you can scroll to the right and divide the value by offset by width to obtain the index of the book and scroll to the corresponding position. If velocity. x = 0, it indicates that the user is unconsciously rolling and the original selection will not change. If velocity. x <0, the user rolls to the left. Modify newOffset. x and return newOffset. This ensures that books are always aligned to the center of the screen.

Compile and run the program. Scroll the cover again and you will notice that the rolling action will become more neat.

To complete this layout, we also need to use a mechanism to restrict users to clicking only the central cover. Currently, no matter which position the cover is clickable.

Open BooksViewController. swift and add the following code under the "// MARK: Helpers" comment:

func selectedCell() -> BookCoverCell? {  if let indexPath = collectionView?.indexPathForItemAtPoint(CGPointMake(collectionView!.contentOffset.x + collectionView!.bounds.width / 2, collectionView!.bounds.height / 2)) {    if let cell = collectionView?.cellForItemAtIndexPath(indexPath) as? BookCoverCell {      return cell    }  }  return nil}

The selectedCell () method returns the center cell.
The code for replacing openBook (_ :) is as follows:

func openBook() {  let vc = storyboard?.instantiateViewControllerWithIdentifier(BookViewController) as! BookViewController  vc.book = selectedCell()?.book  // UICollectionView loads it's cells on a background thread, so make sure it's loaded before passing it to the animation handler  dispatch_async(dispatch_get_main_queue(), { () -> Void in    self.navigationController?.pushViewController(vc, animated: true)    return  })}

Here, we call the new selectedCell method directly and use its book attribute to replace the original book parameter.
Then, replace the collectionView (_: didSelectItemAtIndexPath :) method:

override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {  openBook()}

Here, we simply delete the original code for opening a book at an index, and directly open the current book in the center of the screen.
Compile and run the program. We will see that every time you open a book, it is always in the center of the screen.

 

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.