【譯】UICollectionView 輕松重排
原文鏈接:UICollectionViews Now Have Easy Reordering
原本打算總結一下 UICollectionView 的一些用法,看到一篇比較好的文章,所以直接翻譯了。翻譯得比較生硬,見諒。
我超喜歡UICollectionView
。相比UITableView
,它容易自定義得多。現在我使用甚至使用 collection view 比使用 table view 還要頻繁了。在 iOS9 中,它開始支持使用起來很簡單的重排。在之前是不可能直接重排的,而且實現起來很麻煩。讓我們一起來看看 API。你可以在 Github 上找到對應的 Xcode 項目。
最簡單的實現重排是通過使用UICollectionViewController
。它現在有一個新的屬性叫做installsStandardGestureForInteractiveMovement
,作用是添加手勢(gestures)來重排 cells。這個屬性默認值為True
,這意味著要使用它我們只需要重寫一個方法。
func collectionView(collectionView: UICollectionView,
moveItemAtIndexPath sourceIndexPath: NSIndexPath,
toIndexPath destinationIndexPath: NSIndexPath) {
// move your data order
// 可以留空
}
|
當前的 collection view 判定 items 可以被移動,因為moveItemAtIndexPath
被重寫了。

當我們希望在一個簡單的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()
}
}
</code></pre> </td>
</tr>
</tbody>
</table>
我們保存了在 long press gesture 中不活的被選中的 index path 并且基于它是否有值決定允不允許拖動手勢生效。然后,我們根據手勢狀態調用一些新的 collection view 方法。
beginInteractiveMovementForItemAtIndexPath(indexPath: NSIndexPath) :開始指定位置 cell 的交互移動。
updateInteractiveMovementTargetPosition(targetPosition: CGPoint) :更新交互移動對象的位置
endInteractiveMovement() :在你結束拖動手勢之后結束交互移動
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
</code></pre> </td>
</tr>
</tbody>
</table>
前一個在目標 indexPath 和之前的 indexPath 之間進行移動時調用。另一個類似,不過是在移動結束之后調用。有了這些我們就可以通過一些小手段達到我們的要求。
| |