Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

UICollectionViewのドラッグで、元の位置に戻すときに一瞬ちらつく現象

More than 1 year has passed since last update.

ドラッグ時にちらつく

Xcode9時代にUICollectionViewのドラッグアンドドロップによる並び替え機能を実装していた画面にて、Xcode11.3でビルドしたところ、一見問題なく動いているものの、

  • ドラッグ開始
  • 元の位置に移動する
  • 瞬時に元の位置に戻ったり、ドラッグ位置に戻ったりとちらつく

という現象に遭遇しました。
実はというと、Autolayoutで警告メッセージが表示されていたので、多分そっちを解決すべきなんですが、どうしてもAutolayoutが解決しなかった。

で、iOS11以降から使用できるというUICollectionViewDragDelegate/DropDelegateがあるためこちらに書き換えたところ、現象が解消されました。

UICollectionViewDragDelegate

ドラッグ開始のデリゲート。
UIDragItemのitemProviderを通じてドラッグ後イベントにパラメータを渡したりできる。
よくある書き方はこんなかんじ。

func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
    let index = indexPath.row.description
    let itemProvider = NSItemProvider(object: index as NSString)
    let dragItem = UIDragItem(itemProvider: itemProvider)
    return [dragItem]
}

並び替え処理の場合、このデリゲート内で

func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal
    return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)

と返してあげる。
(ホントわかりにくい)

ドラッグ後のデリゲートはこちら。

func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
    // 遷移先のindexPathはこうして取得
    let destinationIndexPath: IndexPath = coordinator.destinationIndexPath

    switch coordinator.proposal.operation {
        case .move:
            // UIDragItemは複数ある
            let items = coordinator.items
            // 先頭の1要素目から遷移元indexPathの取得はこういう感じで
            let firstIndexPath = items.first!.sourceIndexPath

            // performBatchUpdatesの中で、データの更新とCollectionViewのセルの増減操作をする。
            collectionView.performBatchUpdates({
                // データソースの更新
                let n = datalist.remove(at: sourceIndexPath.item)
                datalist.insert(n, at: destinationIndexPath.item)

                //セルの移動
                collectionView.deleteItems(at: [sourceIndexPath])
                collectionView.insertItems(at: [destinationIndexPath])
            })

            // dropを呼ぶと、指定したindexPathの位置にCellがスッと入る動きをしてくれる
            coordinator.drop(item.dragItem, toItemAt: destinationIndexPath)
        default:
            return
        }
    }
}

という感じ。
あとはUICollectionViewのDrag/DropDelegateを設定すれば実装できる。
ドラッグ中のスタイルの設定はまた別でデリゲートがあります。

※このコードは動作確認してません。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away