Drag And Swip RecyclerView

James Lin
James Lin
Sep 4, 2018 · 6 min read

常常看到 list 的 item 可以藉由 拖曳的方式去改變位置

那麼如何做到這種效果呢?

使用 ItemTouchHelper 就行了哦!!

使用 ItemTouchHelper 需要 override 他的 callback,說說那些方法的 意思ㄅ

getMovementFlags:此方法是用來判斷 item 要往 上 下 左 右 移動,可以用這個方法限制 item 只能 往左(右) 往上(下) 移動。

onMove:此 Item 正在移動,那麼 Adapter 勢必要做出對應的動作,藉由此方法去呼叫 Adapter 改變 Item 的位置。

onSwiped:此 Item 被刪除了,呼叫 Adapter 去刪除資料。

onSelectedChanged:當 Item 被選取時會呼叫此方法,這時藉由此方法呼叫 ViewHolder 改變 background 的顏色。

clearView:當 Item 沒有被選取了或者 滑動取消了,此時會呼叫此方法,藉由此方法將 background 的顏色 回復預設的顏色。

最後將 touchHelper attach 上 RecyclerView 就行瞜。

touchHelper.attachToRecyclerView(recyclerList)

var touchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() {
override fun getMovementFlags(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?): Int {
var dragFlag = ItemTouchHelper.UP or ItemTouchHelper.DOWN
var swipeFlag = ItemTouchHelper.START or ItemTouchHelper.END
return makeMovementFlags(dragFlag, swipeFlag)
}

override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
myAdapter.onItemMove(viewHolder.adapterPosition, target.adapterPosition)
// Log.d("ItemTouch", "From ${viewHolder.adapterPosition} Target ${target.adapterPosition}")
return true
}

override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
myAdapter.onItemDismiss(viewHolder.adapterPosition)
}

override fun isLongPressDragEnabled(): Boolean {
return false
}

override fun isItemViewSwipeEnabled(): Boolean {
return true
}

override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
//only active item to change background
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
if (viewHolder is ItemTouchHelperViewHolder) {
viewHolder.onItemSelected()
}
}
}

override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
super.clearView(recyclerView, viewHolder)
if (viewHolder is ItemTouchHelperViewHolder) {
viewHolder.onItemClear()
}
}
})
touchHelper.attachToRecyclerView(recyclerList)

Adapter

上述有提到說 touchHelper 的 callback 需要 Adapter 對資料與 UI 要有對應的行為

當 Item 在 move 的時候 adapter 需要對每一個 Item 做 交換(swap)的動作

override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
if (fromPosition < toPosition) {
for (i in fromPosition..toPosition - 1) {
Collections.swap(data, i, i + 1)
}
} else {
for (i in fromPosition downTo toPosition + 1) {
Collections.swap(data, i, i + 1)
}
}
notifyItemMoved(fromPosition, toPosition)
return true
}

當資料被刪除的時候,需要將資料 從 list 中移除以及改變 UI

override fun onItemDismiss(position: Int) {
data.removeAt(position)
notifyItemRemoved(position)
}

參考資料:

GitHub

James Lin

Written by

James Lin

live for passion

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade