🔄

【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