I have implemented a collection view as described here. As you can see, it uses the interactive re-ordering of cells of collectionview provided in iOS 9. But the problem is, I cannot control the reordering of cells.
Say the cells are like this -
1 2 3 4
5 6 7 8
9 10 11 12
I want to swap only cell 6 and 4. So after re-ordering the cells will be
1 2 3 6
5 4 7 8
9 10 11 12
Here, In the tutorial, at the beginning of the program, the collection view is like this -
If I put Starbuck on top of Rose Tyler this happens -
Notice that Sarah Connor has Place of Starbuck.
I want to control the reordering of cells so that here Rose Tyler and Starbuck positions will be swapped.
How do I do that?
The simple solution will be to implement your own interactive cell ordering behaviour by simply moving the cell along the pan in screen and swap when gesture ends on another cell's location (with your own animation and data source update ). Here is a working sample:
class ViewController: UIViewController, UICollectionViewDataSource {
var arr: [String] = (0...100).map { return "\($0)" }
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv: UICollectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
cv.register(Cell.self, forCellWithReuseIdentifier: Cell.id)
layout.itemSize = CGSize(width: view.bounds.width/3.5, height: 100)
cv.dataSource = self
cv.addGestureRecognizer(longPressGesture)
return cv
}()
lazy var longPressGesture: UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.handleLongGesture(gesture:)))
private var movingCell: MovingCell?
override func viewDidLoad() {
super.viewDidLoad()
view = collectionView
}
@objc func handleLongGesture(gesture: UILongPressGestureRecognizer) {
var cell: (UICollectionViewCell?, IndexPath?) {
guard let indexPath = collectionView.indexPathForItem(at: gesture.location(in: collectionView)),
let cell = collectionView.cellForItem(at: indexPath) else { return (nil, nil) }
return (cell, indexPath)
}
switch(gesture.state) {
case .began:
movingCell = MovingCell(cell: cell.0, originalLocation: cell.0?.center, indexPath: cell.1)
break
case .changed:
/// Make sure moving cell floats above its siblings.
movingCell?.cell.layer.zPosition = 100
movingCell?.cell.center = gesture.location(in: gesture.view!)
break
case .ended:
swapMovingCellWith(cell: cell.0, at: cell.1)
movingCell = nil
default:
movingCell?.reset()
movingCell = nil
}
}
func swapMovingCellWith(cell: UICollectionViewCell?, at indexPath: IndexPath?) {
guard let cell = cell, let moving = movingCell else {
movingCell?.reset()
return
}
// update data source
arr.swapAt(moving.indexPath.row, indexPath!.row)
// swap cells
animate(moving: moving.cell, to: cell)
}
func animate(moving movingCell: UICollectionViewCell, to cell: UICollectionViewCell) {
longPressGesture.isEnabled = false
UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.1, initialSpringVelocity: 0.7, options: UIViewAnimationOptions.allowUserInteraction, animations: {
movingCell.center = cell.center
cell.center = movingCell.center
}) { _ in
self.collectionView.reloadData()
self.longPressGesture.isEnabled = true
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arr.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: Cell = collectionView.dequeueReusableCell(withReuseIdentifier: Cell.id, for: indexPath) as! Cell
cell.titleLable.text = arr[indexPath.row]
return cell
}
private struct MovingCell {
let cell: UICollectionViewCell
let originalLocation: CGPoint
let indexPath: IndexPath
init?(cell: UICollectionViewCell?, originalLocation: CGPoint?, indexPath: IndexPath?) {
guard cell != nil, originalLocation != nil, indexPath != nil else { return nil }
self.cell = cell!
self.originalLocation = originalLocation!
self.indexPath = indexPath!
}
func reset() {
cell.center = originalLocation
}
}
final class Cell: UICollectionViewCell {
static let id: String = "CellId"
lazy var titleLable: UILabel = UILabel(frame: CGRect(x: 0, y: 20, width: self.bounds.width, height: 30))
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(titleLable)
titleLable.backgroundColor = .green
backgroundColor = .white
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
}
For reordering of collection view item we need to add Long press gesture on collection view . and for reordering the collection View item with a particular indexPath, UICollectionViewDelegate provide the "targetIndexPathForMoveFromItemAt" method. And for getting the complete tutorial you follow this one Reordering CollectionView Item
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With