🔄

【Android】RecyclerViewのアイテムをドラッグアンドドロップで並び替える

2024/02/29に公開

導入

Androidでリストアイテムをドラッグアンドドロップ操作で並び替える実装方法についてご紹介します。
ToDoリストやタスク管理アプリなどで、タスクを完了したり、タスクを並び替えて優先度を変更する操作がイメージしやすいかと思います。
RecyclerViewとItemTouchHelper.SimpleCallbackを使えば簡単に実装できます。

ItemTouchHelper.SimpleCallbackとは

ItemTouchHelperは、RecyclerViewのアイテムを操作するためのユーティリティクラスです。
ItemTouchHelperを使う際には、ItemTouchHelper.Callbackクラスのオブジェクトをコンストラクタに渡す必要があります。
Callbackクラスをそのまま実装することもできますが、Androidではドラッグアンドドロップとスワイプの処理に特化したシンプルなラッパーであるItemTouchHelper.SimpleCallbackクラスが用意されていますので、今回はこちらを使用します。

実装例

以下は、上下方向にドラッグアンドドロップでリストアイテムの位置を変更できるよう実装した例です。

// ItemTouchHelperオブジェクト生成
val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(
    ItemTouchHelper.UP or ItemTouchHelper.DOWN,
    ItemTouchHelper.ACTION_STATE_IDLE
) {
    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
        // ドラッグ操作が開始されたときの処理
        // 以下、サンプル
        val fromPosition = viewHolder.absoluteAdapterPosition
        val toPosition = target.absoluteAdapterPosition
        presenter.swap(fromPosition, toPosition)
        binding.recyclerView.adapter?.notifyItemMoved(fromPosition, toPosition)
        
        return true
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        // スワイプされたアイテムの処理
    }
})

// RecyclerViewにセット
itemTouchHelper?.attachToRecyclerView(binding.recyclerView)

onMove

ItemTouchHelperがドラッグされた項目を古い位置から新しい位置に移動するときに呼び出されます。
onMoveメソッドのパラメータは

  • 第1引数: ItemTouchHelperがアタッチされているRecyclerView
  • 第2引数: ドラッグ開始時のviewHolder
  • 第3引数: ドラッグ完了時のviewHolder

となります。
ここからドラッグアンドドロップ開始時のポジションと完了時のポジションを取得し、データの入れ替え処理を行っています。
処理が完了したらnotifyItemMovedメソッドを呼び出して、Adapterにリストアイテムが移動されたことを通知します。

onSwiped

リストアイテムをスワイプすると呼び出されます。
サンプルコードでは並び替えのみ対応しているので処理を行っていませんが、スワイプされたアイテムに対し行いたい操作(削除など)を行います。

注意点

大量のアイテムを含むリストを操作する場合、パフォーマンスの問題が発生する可能性があります。
Adapterがドラッグアンドドロップ完了通知を受け取ったら、保持しているリストデータを更新し、その変更を再度Viewに反映させる必要があります。
ただし、パフォーマンスの観点から、notifyItemChangedメソッドなどを用いて変更があったアイテムのみを更新するように制限することが重要です。

参考

https://developer.android.google.cn/reference/kotlin/androidx/recyclerview/widget/ItemTouchHelper.SimpleCallback?hl=en

https://qiita.com/ryo_mm2d/items/973b056b52b111bb58d4

Discussion