LoginSignup
88

More than 5 years have passed since last update.

[Swift] CollectionViewは、簡単にドラッグ&ドロップで移動できる?

Last updated at Posted at 2016-08-17

はじめに

iOS9以上のみのサポートですが、
CollectionViewCellを簡単に移動できるメソッドがあることを最近知りましたので、
共有します。(遅)

動作イメージ

output.gif

サンプルコード

まずは、サンプルコードを御覧ください。
CollectionViewの実装自体は、特別なことをしていません。
ロングタップのジェスチャー部分に注目してください。

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!
    private var numbers = [Int]()

    override func viewDidLoad() {
        super.viewDidLoad()

        numbers = loadTestData()
        addEventListner()
    }

    //ダミーデータです
    private func loadTestData() -> [Int]{

        for i in 1...100 {
            numbers.append(i)
        }
        return numbers
    }

    private func addEventListner() {
        let longPressGesture = UILongPressGestureRecognizer(target: self,
                                                            action: #selector(self.handleLongGesture(_:)))
        collectionView.addGestureRecognizer(longPressGesture)
    }

    //ここがポイントです
    func handleLongGesture(gesture: UILongPressGestureRecognizer) {

        switch(gesture.state) {

        case UIGestureRecognizerState.Began:
            guard let selectedIndexPath = collectionView.indexPathForItemAtPoint(gesture.locationInView(collectionView)) else {
                break
            }
            collectionView.beginInteractiveMovementForItemAtIndexPath(selectedIndexPath)

        case UIGestureRecognizerState.Changed:
            collectionView.updateInteractiveMovementTargetPosition(gesture.locationInView(gesture.view!))

        case UIGestureRecognizerState.Ended:
            collectionView.endInteractiveMovement()

        default:
            collectionView.cancelInteractiveMovement()
        }
    }
}

extension ViewController: UICollectionViewDataSource {

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return numbers.count
    }

    func collectionView(collectionView: UICollectionView,
                        cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(LabelCollectionViewCell.reuseIdentifier,
                                                                         forIndexPath: indexPath) as! LabelCollectionViewCell
        cell.number = numbers[indexPath.item]
        return cell
    }

    func collectionView(collectionView: UICollectionView,
                        moveItemAtIndexPath sourceIndexPath: NSIndexPath,
                        toIndexPath destinationIndexPath: NSIndexPath) {

        let tempNumber = numbers.removeAtIndex(sourceIndexPath.item)
        numbers.insert(tempNumber, atIndex: destinationIndexPath.item)
    }
}

UILabelだけのCollectionViewCellです。

LabelCollectionViewCell.swift
import UIKit

protocol ReusableView: class {}

extension ReusableView where Self: UIView {
    static var reuseIdentifier: String {
        return String(self)
    }
}

class LabelCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var numberLabel: UILabel!
    var number = 0 {

        didSet {
            numberLabel.text = "\(number)"
        }
    }
}

extension LabelCollectionViewCell: ReusableView {}


ちょっと解説

ドラッグ&ドロップの機能は、ロングタップのジェスチャーと連動して、
下記のメソッドを呼ぶだけです。

メソッド名 説明
beginInteractiveMovementForItemAtIndexPath(indexPath: NSIndexPath) 移動開始
updateInteractiveMovementTargetPosition(targetPosition: CGPoint) 移動中
endInteractiveMovement() 移動終了
cancelInteractiveMovement() 移動の取り消し

まとめ

iOS10の正式リリース間近ですが、
iOS9でも知らない機能がまだまだあるようです。

iOS8までは、ドラッグ&ドロップの実装は大変でしたが、
iOS9では簡単にできるようになっていたようです。(遅 2回目)

iPhone標準カレンダーのような実装ができるように鍛錬したいと思います。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
88