本文原链:【译】UICollectionView 轻松重排
原文连接:UICollectionViews Now Have Easy Reorderinggit本来打算总结一下 UICollectionView 的一些用法,看到一篇比较好的文章,因此直接翻译了。翻译得比较生硬,见谅。github
我超喜欢UICollectionView
。相比UITableView
,它容易自定义得多。如今我使用甚至使用 collection view 比使用 table view 还要频繁了。在 iOS9 中,它开始支持使用起来很简单的重排。在以前是不可能直接重排的,并且实现起来很麻烦。让咱们一块儿来看看 API。你能够在 Github 上找到对应的 Xcode 项目。ide
最简单的实现重排是经过使用UICollectionViewController
。它如今有一个新的属性叫作installsStandardGestureForInteractiveMovement
,做用是添加手势(gestures)来重排 cells。这个属性默认值为True
,这意味着要使用它咱们只须要重写一个方法。ui
func collectionView(collectionView: UICollectionView, moveItemAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) { // move your data order // 能够留空 }
当前的 collection view 断定 items 能够被移动,由于moveItemAtIndexPath
被重写了。spa
当咱们但愿在一个简单的UIViewController
中使用 collection view 时,会麻烦一点。咱们也要实现以前提到的UICollectionViewDataSource
方法,不过咱们须要重写installsStandardGestureForInteractiveMovement
。不用担忧,也很简单。UILongPressGestureRecognizer
是一种持续性的手势识别器而且彻底支持拖动。翻译
override func viewDidLoad() { super.viewDidLoad() longPressGesture = UILongPressGestureRecognizer(target: self, action: "handleLongGesture:") self.collectionView.addGestureRecognizer(longPressGesture) } func handleLongGesture(gesture: UILongPressGestureRecognizer) { switch(gesture.state) { case UIGestureRecognizerState.Began: guard let selectedIndexPath = self.collectionView.indexPathForItemAtPoint(gesture.locationInView(self.collectionView)) else { break } collectionView.beginInteractiveMovementForItemAtIndexPath(selectedIndexPath) case UIGestureRecognizerState.Changed: collectionView.updateInteractiveMovementTargetPosition(gesture.locationInView(gesture.view!)) case UIGestureRecognizerState.Ended: collectionView.endInteractiveMovement() default: collectionView.cancelInteractiveMovement() } }
咱们保存了在 long press gesture 中不活的被选中的 index path 而且基于它是否有值决定允不容许拖动手势生效。而后,咱们根据手势状态调用一些新的 collection view 方法。code
beginInteractiveMovementForItemAtIndexPath(indexPath: NSIndexPath)
:开始指定位置 cell 的交互移动。对象
updateInteractiveMovementTargetPosition(targetPosition: CGPoint)
:更新交互移动对象的位置blog
endInteractiveMovement()
:在你结束拖动手势以后结束交互移动rem
cancelInteractiveMovement()
:取消交互移动
这些让搞定拖动手势很是容易。
效果和标准的UICollectionViewController
同样。很酷对吧,不过更酷的是咱们能够将咱们自定义的 collection view layout 应用到重排中去。看看下面在简单的瀑布视图中的交互移动。
嗯,看起来不错,不过若是咱们不想在移动的时候改变 cell 大小呢?选中的 cell 大小应该在交互移动时保持一致。这是能够实现的。UICollectionViewLayout
也有一些其余的方法来负责重排。
func invalidationContextForInteractivelyMovingItems(targetIndexPaths: [NSIndexPath], withTargetPosition targetPosition: CGPoint, previousIndexPaths: [NSIndexPath], previousPosition: CGPoint) -> UICollectionViewLayoutInvalidationContext func invalidationContextForEndingInteractiveMovementOfItemsToFinalIndexPaths(indexPaths: [NSIndexPath], previousIndexPaths: [NSIndexPath], movementCancelled: Bool) -> UICollectionViewLayoutInvalidationContext
前一个在目标 indexPath 和以前的 indexPath 之间进行移动时调用。另外一个相似,不过是在移动结束以后调用。有了这些咱们就能够经过一些小手段达到咱们的要求。
internal override func invalidationContextForInteractivelyMovingItems(targetIndexPaths: [NSIndexPath], withTargetPosition targetPosition: CGPoint, previousIndexPaths: [NSIndexPath], previousPosition: CGPoint) -> UICollectionViewLayoutInvalidationContext { var context = super.invalidationContextForInteractivelyMovingItems(targetIndexPaths, withTargetPosition: targetPosition, previousIndexPaths: previousIndexPaths, previousPosition: previousPosition) self.delegate?.collectionView!(self.collectionView!, moveItemAtIndexPath: previousIndexPaths[0], toIndexPath: targetIndexPaths[0]) return context }
解决方案很是清晰。获取正在移动的 cell 以前和目标 index path。而后调用UICollectionViewDataSource
来移动这些 item。
不用怀疑,collection view 重排是一个很是棒的更新。UIKit 工程师干得太棒了!:)