Drag And Swip RecyclerView

James Lin
6 min readSep 4, 2018

--

常常看到 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
James Lin

No responses yet