はじめに
こんにちは。Yossyです。
前回まではCollectionViewのカスタムレイアウトを作成していました。
このCollectionViewのセルの並び替え処理を実装をしたので、備忘録ついでに紹介したいと思います。
実装方法
自分が作成した時は要件の都合上、CollectionViewからセル(カスタムクラス実装)自体を取得し、セルが持つプロパティ(並び順含む)をDBに保存していました。そして、次にCollectionViewを表示する際にDBから並び順を含めたプロパティを読み出して使用するという流れです。
手順
①ロングタップの実装
②並び替え可とする実装
③並び替え時のデータ処理
ロングタップの実装
ロングタップジェスチャーを追加します。
ロングタップでセルを並び替えて、指を離すと並び替えが完了します。
移動するセルのインスタンスをプロパティに入れて保持しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | override func viewDidLoad() { super.viewDidLoad() // ロングタップジェスチャーを付与 addLongTapGesture() } // 長押しでCollectionViewのセル移動処理を行う func addLongTapGesture() { let longTapGesture = UILongPressGestureRecognizer(target: self, action: #selector(longTap(gesture:))) collectionView.addGestureRecognizer(longTapGesture) } @objc func longTap(gesture: UILongPressGestureRecognizer) { switch gesture.state { // ロングタップの開始時 case .began: guard let selectedIndexPath = collectionView.indexPathForItem(at: gesture.location(in: collectionView)) else { break } let movingCell = collectionView.cellForItem(at: selectedIndexPath) as! CustomCell // 並び替えるセルのインスタンスを保持 celltoMove = movingCell collectionView.beginInteractiveMovementForItem(at: selectedIndexPath) // セルの移動中 case .changed: collectionView.updateInteractiveMovementTargetPosition(gesture.location(in: gesture.view)) // セルの移動完了時 case .ended: collectionView.endInteractiveMovement() default: collectionView.cancelInteractiveMovement() } } |
並び替えを可とする
デリゲートメソッドcollectionView(_:canMoveItemAt:)で
true
を返します。
1 2 3 4 | // 並び替えを可とする func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool { return true } |
並び替え時のデータ処理
セルが移動された際に呼ばれるデリゲートメソッドcollectionView(_:moveItemAt:to:)を実装します。
ここで、CollectionView内のセルを取得し、配列に格納して、DBへの保存処理を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // 並び替え時の処理 func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { // セル格納用の配列 var cellsArray:[CustomCell] = [] // CollectionViewに表示中のセルを取得 for i in 0...collectionView.visibleCells.count { // 移動中のセルは、visibleCellsでは取得できない為スキップ if i == destinationIndexPath.row { continue } // セルを配列に格納、orderプロパティに並び順を格納 let cell = collectionView.cellForItem(at: IndexPath(item: i, section: 0)) as! CustomCell cell.order = i cellsArray.append(cell) } // visibleCellsで取得漏れしてるセルを配列に追加 let cellToMove = celltoMove as! CustomCell cellToMove.order = destinationIndexPath.row cellsArray.insert(cellToRemove, at: destinationIndexPath.item) // DBへの保存処理 logicClass.updateCellsOrder(cells: cellsArray) } |
次回表示時
DBからセルの取得処理を行って、order順に表示してあげます。
1 2 3 4 5 6 7 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { // DBからセル取得し、order順に並び替え let cells = logicClass.getCellsfromDB() cells.sort{ $0.order > $1.order } return cells[indexPath.row] } |
他に
iOS11以降であれば、UICollectionViewDragDelegateとUICollectionViewDropDelegateを利用した実装方法も可能です。
機会があれば、こちらも紹介したいと思います。
さいごに
シンプルな並び替え実装は難しくないですが、色々と要件が重なると途端に難しくなりますね。色々な実装パターンを知っておいて、使い分けしたいですね。