【譯】UICollectionView 輕鬆重排

本文原鏈:【譯】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 工程師幹得太棒了!:)

相關文章
相關標籤/搜索