Unyablog.

のにれんのブログ

RecyclerView で Drag と Swipe をサクッと実装

RecyclerView で並び換えや項目の消去をする UI を作成するには、ItemTouchHelper を用いると非常に楽です。

これを使うと、

  • 長押しからの移動で並び替え
  • スワイプで消去をする

といった処理を行えます。

Kotlin での実装

val helper = ItemTouchHelper(object : ItemTouchHelper.Callback() {
    // どのような動きを許可するか
    // ViewHolder ごとに分ける等の場合はここで制御する
    override fun getMovementFlags(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?): Int {
        return makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT)
    }

    // 動いた場合
    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
        // アイテムの位置を変更
        val button = adapter.buttonList.removeAt(viewHolder.adapterPosition)
        adapter.buttonList.add(target.adapterPosition, button)
        adapter.notifyDataSetChanged()
        return true
    }

    // スワイプされた場合
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        // 項目を消去
        adapter.buttonList.removeAt(viewHolder.adapterPosition)
        adapter.notifyDataSetChanged()
    }

    // 選択状態が変化した時に呼ばれる
    // 選択が解除された場合 viewHolder は null になるので #clearView で操作する
    override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
        super.onSelectedChanged(viewHolder, actionState)
        // e.g. 半透明にする
        when (actionState) {
            ItemTouchHelper.ACTION_STATE_DRAG, ItemTouchHelper.ACTION_STATE_SWIPE -> {
                (viewHolder as? OptionButtonsPreferenceRecyclerAdapter.ViewHolder)?.let {
                    it.binding.itemBaseView.alpha = 0.5f
                }
            }
        }
    }

    // アニメーションが終了する時に呼ばれる
    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
        super.clearView(recyclerView, viewHolder)
        // e.g. 反透明にしていたのを元に戻す
        (viewHolder as OptionButtonsPreferenceRecyclerAdapter.ViewHolder).binding.itemBaseView.alpha = 1.0f
    }
})

helper.attachToRecyclerView(recyclerView)

PhotoLinkViewer-Core/PLVOptionButtonPreferenceActivity.kt at 63fb7a73f7eaded1d8801e5a63bcc65965829b28 · nonylene/PhotoLinkViewer-Core · GitHub

こうするだけで下のように良い感じに移動・消去できるようになります。すごく便利。

補足

  • OptionButtonsPreferenceRecyclerAdapter.ViewHolder に無理矢理キャストしているのはこの ViewHolder しか存在しないため
  • notifyDataSetChagned() でもいい感じにアニメーションしているのは、以下の記事のように特定の ID を返しているため