简体   繁体   中英

How to make paging animation for a collectionView cell scrolling to center?

I am using swift 3 to write an app which has a UIViewController looks like the following picture. It contains a horizontal-scrollable collectionView (the blue block) on the top, and its functionality is to switch between different labels(first, prev, current, next, last...etc, the total amount of labels are not fixed). What I need to achieve is that on scrolling (or panning) the collection view, the 'NEXT' or 'PREV' should move (and anchor automatically) to the center with velocity similar to paging animation. How could I achieve this? Currently I use the Paging Enabled attribute of the scrollView , however this only work when there is one label in the window.

Similar features may look like the middle "albums" section of iTunes app, which the collectionView cell would scroll to some pre-defined point automatically with some animation once it detects any swipe/pan gesture.

在此处输入图片说明

according to your comment if you want to do the Tap to select thing there are 2 things you need to do

1- Disable Collection View Scrolling in viewDidLoad

collectionView.isScrollingEnabled = false 

2- Display Selected Cell in Center , add this in your didSelectItemAtIndexPath method

 func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

collection.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizantally)

let cell  = collectionView.cellForItem(at : indexPath) as! YourCollectionViewCellClass
cell.titleLable.font = UIFont.boldSystemFont(ofSize : 20)
}

Thanks to Raheel's answer here , I finally find a way for a desirable scroll effect. Some key functions are listed as follow in swift:

  1. First, disable Paging Enabled attribute of the scrollView
  2. Define setIdentityLayout() and setNonIdentityLayout() which defines the layouts of both selected / non-selected cell (for example, MyCollectionViewCell in this case)

  3. Define some related properties such as:

     lazy var COLLECTION_VIEW_WIDTH: CGFloat = { return CGFloat(self.collectionView.frame.size.width / 2) }() fileprivate let TRANSFORM_CELL_VALUE = CGAffineTransform(scaleX: 1, y: 1) // Or define other transform effects here fileprivate let ANIMATION_SPEED = 0.2 
  4. implement the following key methods for UIScrollViewDelegate :

     func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { // Do tableView data refresh according to the corresponding pages here } func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { // Scroll to corresponding position let pageWidth: Float = Float(COLLECTION_VIEW_WIDTH) // width + space let currentOffset: Float = Float(scrollView.contentOffset.x) let targetOffset: Float = Float(targetContentOffset.pointee.x) var newTargetOffset: Float = 0 if targetOffset > currentOffset { newTargetOffset = ceilf(currentOffset / pageWidth) * pageWidth } else { newTargetOffset = floorf(currentOffset / pageWidth) * pageWidth } if newTargetOffset < 0 { newTargetOffset = 0 } else if (newTargetOffset > Float(scrollView.contentSize.width)){ newTargetOffset = Float(Float(scrollView.contentSize.width)) } targetContentOffset.pointee.x = CGFloat(currentOffset) scrollView.setContentOffset(CGPoint(x: CGFloat(newTargetOffset), y: scrollView.contentOffset.y), animated: true) // Set transforms let identityIndex: Int = Int(newTargetOffset / pageWidth) var cell = delegate!.roomCollections.cellForItem(at: IndexPath.init(row: identityIndex, section: 0)) as? MyCollectionViewCell UIView.animate(withDuration: ANIMATION_SPEED, animations: { cell?.transform = CGAffineTransform.identity cell?.setIdentityLayout() }) // right cell cell = delegate!.roomCollections.cellForItem(at: IndexPath.init(row: identityIndex + 1, section: 0)) as? MyCollectionViewCell UIView.animate(withDuration: ANIMATION_SPEED, animations: { cell?.transform = self.TRANSFORM_CELL_VALUE cell?.setNonIdentityLayout() }) // left cell, which is not necessary at index 0 if (identityIndex != 0) { cell = delegate!.roomCollections.cellForItem(at: IndexPath.init(row: identityIndex - 1, section: 0)) as? MyCollectionViewCell UIView.animate(withDuration: ANIMATION_SPEED, animations: { cell?.transform = self.TRANSFORM_CELL_VALUE cell?.setNonIdentityLayout() }) } } 
  5. Finally, define initial layout in func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) :

     if (indexPath.row == 0 && /* other first item selected condition */) { cell.setIdentityLayout() } else { cell.transform = TRANSFORM_CELL_VALUE cell.setNonIdentityLayout() } 

To add touch scroll effect, simply add target to each collection views, and do similar calculation which changes the contentOffSet of the scrollView , which is omitted here because this feature is simpler and not the primary question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM