はじめに
ここでは、RecyclerViewのアイテムをスワイプ削除する方法について書いていきます。 これまでの実装については前回を参照してください。
目標
今回は下のGIFのようにRecyclerViewのアイテムをスワイプで削除できようにします。
実装
Gradleには、特に追加するものはありません。
Activity
削除機能を実装するためのコードを、今回はActivityに書きました。
class MainActivity : AppCompatActivity() {
...
private val swipeToDismissTouchHelper by lazy {
getSwipeToDismissTouchHelper(adapter)
}
override fun onCreate(savedInstanceState: Bundle?) {
...
swipeToDismissTouchHelper.attachToRecyclerView(main_recycler_view)
...
}
private fun getSwipeToDismissTouchHelper(adapter: RecyclerAdapter) =
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(
ItemTouchHelper.ACTION_STATE_IDLE,
ItemTouchHelper.RIGHT
) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val timeTasks = adapter.getItems()
mainViewModel.delete(timeTasks[viewHolder.adapterPosition])
}
override fun onChildDraw(
c: Canvas,
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
dX: Float,
dY: Float,
actionState: Int,
isCurrentlyActive: Boolean
) {
super.onChildDraw(
c,
recyclerView,
viewHolder,
dX,
dY,
actionState,
isCurrentlyActive
)
val itemView = viewHolder.itemView
val background = ColorDrawable(Color.RED)
val deleteIcon = AppCompatResources.getDrawable(
this@MainActivity,
R.drawable.ic_baseline_delete_36
)
val iconMarginVertical =
(viewHolder.itemView.height - deleteIcon!!.intrinsicHeight) / 2
deleteIcon.setBounds(
itemView.left + iconMarginVertical,
itemView.top + iconMarginVertical,
itemView.left + iconMarginVertical + deleteIcon.intrinsicWidth,
itemView.bottom - iconMarginVertical
)
background.setBounds(
itemView.left,
itemView.top,
itemView.right + dX.toInt(),
itemView.bottom
)
background.draw(c)
deleteIcon.draw(c)
}
})
}
なんかともて長いコードになってしまった。
細分化して、何をしているか見ていきます。
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(
ItemTouchHelper.ACTION_STATE_IDLE,
ItemTouchHelper.RIGHT
)
ItemTouchHelper()
はRecyclerViewでドラッグ&ドロップやスワイプ機能を実現するためのクラスです。
ユーザの操作に対してCallbackを受け取る必要があるので、それを簡単に実装できるItemTouchHelper.SimpleCallback()
を使用しました。
ItemTouchHelper.SimpleCallback()
は第一引数にドラッグを有効にする向きを指定し、第二引数でスワイプを有効にする向きを指定します。今回は、ドラッグは行わないのでItemTouchHelper.ACTION_STATE_IDLE
を指定し、スワイプは右スワイプ(ItemTouchHelper.RIGHT
)のみを有効にします。
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
onMove()
では、ドラッグの処理を書くのですが今回はドラッグの処理はないので何も変更なしです。
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val timeTasks = adapter.getItems()
mainViewModel.delete(timeTasks[viewHolder.adapterPosition])
}
onSwiped()
では、スワイプ時の処理を書きます。
スワイプ時にadapterからアイテムを要求し、スワイプされたアイテムをviewModelに渡しています。
override fun onChildDraw(
c: Canvas,
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
dX: Float,
dY: Float,
actionState: Int,
isCurrentlyActive: Boolean
)
onChildDraw()
では、スワイプ時の背景やアイコンの設定ができます。(他にも方法はあるらしい)
変数を定義
val itemView = viewHolder.itemView // RecyclerViewのitemView
val background = ColorDrawable(Color.RED) // スワイプ時の背景の定義
val deleteIcon = AppCompatResources.getDrawable( // スワイプ時に出てくるアイコンを定義
this@MainActivity,
R.drawable.ic_baseline_delete_36
)
// アイコンを表示させる位置を決めるためのマージンを計算(今回は縦方向の中心)
val iconMarginVertical =
(viewHolder.itemView.height - deleteIcon!!.intrinsicHeight) / 2
最後に、背景とアイコンを適切な位置で表示させます。
deleteIcon.setBounds(
itemView.left + iconMarginVertical,
itemView.top + iconMarginVertical,
itemView.left + iconMarginVertical + deleteIcon.intrinsicWidth,
itemView.bottom - iconMarginVertical
)
background.setBounds(
itemView.left,
itemView.top,
itemView.right + dX.toInt(),
itemView.bottom
)
background.draw(c)
deleteIcon.draw(c)