一, Foreword

I am a big fan of UICollectionView. This class is more customizable than its older UITableView class. Now I use the collection view more often than with the table view. With the advent of iOS 9, it supports simple rearrangement. Prior to this, rearrangement could not have a ready-made approach, and doing so was a painful job. Now let's take a look at the API, you can download the source code of this project to see the specific implementation process.

二, Implementation process

The easiest way to add a simple reflow is to use UICollectionViewController. It now has a new property called installsStandardGestureForInteractiveMovement (which sets standard gestures for interactive mobile work), and the addition of this property allows us to reorder cell units with standard gestures. The default value of this property is true, which means that we only need to override a method to make it work.

override func collectionView(collectionView: UICollectionView,
    moveItemAtIndexPath sourceIndexPath: NSIndexPath,
    toIndexPath destinationIndexPath: NSIndexPath) {
    // move your data order
}

Collection view concludes that each item (element) can be moved because the moveItemAtIndexPath function is overloaded.

Things get more complicated when we want to use a simple UIViewController with a collection view. We also need to implement the UICollectionViewDataSource method mentioned earlier, but we need to override installsStandardGestureForInteractiveMovement. Don't worry, these are easy to support. UILongPressGestureRecognizer is a continuous, fully supported panning gesture recognizer.

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()
        }
    }
 ```We have stored the selected index path, which is obtained from `longPressGesture handler`(long-press gesture processor). This path also depends on whether it has any allowable , the value associated with the pan gesture. Next, we call some new `collection view`methods based on the state of the gesture: * `beginInteractiveMovementForItemAtIndexPath(indexPath: NSIndexPath)?`Starting `cell`(unit) on a specific index path `Interactive Movement交互式移动工作)。

* `updateInteractiveMovementTargetPosition(targetPosition: CGPoint)?|| @@`(Interactive mobile work). `endInteractiveMovement()?`Updates the target position of the interactive move during gestures. 】

*`cancelInteractiveMovement()?`End interactive move after completing gestures

*`Interactive Movement`Cancel ![](http://www.demodashi.com/contentImages/image/20180518/`. This makes it easier to understand the pan gestures. `UICollectionViewController18VhpxqmaSUB3A0o1SV.gif)

The machine response is the same as the standard `collection view layout`, it's really cool, but there is even more cool - we can apply for the custom `waterfall layout`(collection collection view layout) Row, the following is a test of `Interactive Movement` in ![](http://www.demodashi.com/contentImages/image/`( waterfall layout). `cell20180518/Aftf6aBfxqDWOHsCwAN.gif)

Well, it looks cool, but what if we don't want to change their size when moving `cell`( units)? The size of the selected `Interactive Movement`( unit) should remain the same during `UICollectionViewLayout`. This is feasible. ```swift
func invalidationContextForInteractivelyMovingItems(targetIndexPaths: [NSIndexPath],
    withTargetPosition targetPosition: CGPoint,
    previousIndexPaths: [NSIndexPath],
    previousPosition: CGPoint) -> UICollectionViewLayoutInvalidationContext


func invalidationContextForEndingInteractiveMovementOfItemsToFinalIndexPaths(indexPaths: [NSIndexPath],
    previousIndexPaths: [NSIndexPath],
    movementCancelled: Bool) -> UICollectionViewLayoutInvalidationContext
 ``` There are additional ways to handle rearrangement. `Interactive Movement` The first function is called during the `target` of the element with `cell`(target element) and the previous `indexPaths` @|@@`(index address) of . The second is similar to the first function, but it is only called after the end of `Interactive Movement`. With this knowledge we can achieve our needs with a little trick.





<div class="se-preview-section-delimiter"></div>

```swift
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
}

Get the previous and target index paths of the currently moving cell, then call the UICollectionViewDataSource method to move these item(element).

毫无疑问,collection view的重排是一个出色的附加功能,UIKit前端框架工程师干得漂亮!:)

三, project structure diagram

四,后记

暂无了 UICollectionViews has a simple reflow function