【译】UICollectionView 轻松重排

本文原链:【译】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()
        }
    }

我们保存了在 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],movementCancelled: Bool) -> UICollectionViewLayoutInvalidationContext

一个在目标 indexPath 和之前的 indexPath 之间进行移动时调用。另一个类似,不过是在移动结束之后调用。有了这些我们就可以通过一些小手段达到我们的要求。

internal override func invalidationContextForInteractivelyMovingItems(targetIndexPaths: [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 工程师干得太棒了!:)

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...