Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reordering UICollectionView in iOS7

I want to build a UICollectionView, or use something similar library to make grid view, in which i can rearrange cells. My app supports iOS 7, and, unfortunately UICollectionView method - (BOOL)beginInteractiveMovementForItemAtIndexPath:(NSIndexPath *)indexPath is only available on iOS 9 and later.

Is there any way i can achieve the effect of 'drag and reorder' collection view cells on iOS7? Thanks.

like image 334
Evgeniy Kleban Avatar asked Apr 24 '16 09:04

Evgeniy Kleban


1 Answers

Well, I happened to come across the very same issue, so let me add my two cents on this.

In order to achieve to get the same effect of what UIKit does when rearranging cells, I followed a more or less similar approach described below:

  1. Add a long-press gesture recognizer into collection view so that you’d be able to detect which cell was tapped without messing up with collectionView:didSelectItemAtIndexPath method.

  2. When user long-presses on a cell, take a screenshot of that cell, add the snapshot view into collection view and then hide the cell. As the user moves his finger on the screen, update the snapshot’s center to move it programmatically so it will look like the user is dragging the cell.

  3. The trick is to decide when and how to swap cells. As the snapshot moves around, it will intersect with other cells. When it happens, you should update your data source and call moveItemAtIndexPath so it will swap the positions of original cell and the cell which the snapshot intersects.

  4. When dragging ends, remove the snapshot from collection view and show the original cell.

You can map those steps to gesture recognizer’s states, so that we know what you should do at each state:

  • Began: 1
  • Changed: 2, 3
  • Ended, Cancelled, Failed: 4

I put an example project in my github account, so you can download and play around with it. Here, I will just implement the gesture callback:

Note: The below code may not work because I threw away some implementation specific details. But it should show the basic intent. Please download the full code from my github repo.

func longPressRecognized(recognizer: UILongPressGestureRecognizer) {
  let location = recognizer.locationInView(collectionView)
  let indexPath = collectionView.indexPathForItemAtPoint(location)

  switch recognizer.state {
    case .Began:
      let cell = collectionView.cellForRowAtIndexPath(indexPath)
      let snapshotView = cell.snapshotViewAfterScreenUpdates(true)
      snapshot.center = cell.center
      collectionView.addSubview(snapshotView)
      cell.contentView.alpha = 0.0 // hides original cell

    case .Changed:
      snapshotView.center = location // will follow user's finger.      
      dataSource.swap(originalCellIndexPath.item, indexPath.item) // swaps data
      collectionView.moveItemAtIndexPath(originalCellIndexPath, toIndexPath: indexPath) // swaps cells
      originalCellIndexPath = indexPath

    default:
      let cell = cellForRowAtIndexPath(originalCellIndexPath)
      cell.contentView.alpha = 1.0
      snapshotView.removeFromSuperview()
  }
}

Here is the effect you will get (recorded on iOS 8.4 Simulator):

enter image description here

like image 125
Ozgur Vatansever Avatar answered Nov 20 '22 18:11

Ozgur Vatansever