RecyclerView 使用ItemTouchHelper實現滑動刪除、拖移改變順序效果
前置作業創建RecyclerView、Adapter我這邊就不贅述了
我們會使用到ItemTouchHelper工具類別
但這一步驟所做的只是讓單一列表項目有被拖拉跟swipe的效果,其他的列表項目並沒有跟著移動。
不過上面的動作只是畫面做了更動,實際上列表的資料Model並沒有真的做了移動,所以在拖放之後,如果滾動列表,會發現列表項目又恢復移動前的排列位置。
加入資料Model更新的程式碼之後,整個程式碼大致如下面兩個區塊, 在此範例中,我將資料更新與通知列表更新的動作放在自行實作的Adapter的public函式moveItem()
效果如下:
同上下拖拉一樣,目前的程式碼也只是讓畫面有效果,但還沒有連同資料model一起更新,所以會發現畫面上的列表下方好像怪怪的。 所以需要再調整成如下的程式碼,在此我將刪除項目的動作放在自行實作的Adapter的public函式removeItem()
最後效果如下圖:
直接進入主題
官方解釋:這是一個實用工具類,用於添加滑動以關閉和拖放支持到RecyclerView。
這是一個支持RecyclerView滑動刪除和拖拽的實用工具類
如何使用:
SimpleCallback建立時,需要指定想要支援的拖拉(move)與swipe的方向,在此範例我們讓他可以上下拖拉跟左右swipe(或用START、END,則可支援右到左方向的排列), 而主要需要實作的函式有分別對應到拖拉與swipe的onMove與onSwipe。
private void setUpRecyclerView() {
adapter = new ContactAdapter(options);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
// 實現拖移、左右滑動刪除的效果
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP | ItemTouchHelper.DOWN,
ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder viewHolder1) {
// 上下拖移callback
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
// 左右滑動callback
}
}).attachToRecyclerView(recyclerView);
}
做完以上動作,RecyclerView已經有上下拖拉跟左右swipe效果了,如下面圖示。但這一步驟所做的只是讓單一列表項目有被拖拉跟swipe的效果,其他的列表項目並沒有跟著移動。
加入拖拉時其他項目的效果與資料更新
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
// Step 2-1
final int fromPos = viewHolder.getAdapterPosition();
final int toPos = target.getAdapterPosition();
// move item in `fromPos` to `toPos` in adapter.
adapter.notifyItemMoved(fromPos, toPos);
return true;// true if moved, false otherwise
}
做完以上動作,拖拉項目時就能有如下圖的效果,可以看到其他項目會跟著移動,且放開項目之後,該項目真的會停留在目標位置。不過上面的動作只是畫面做了更動,實際上列表的資料Model並沒有真的做了移動,所以在拖放之後,如果滾動列表,會發現列表項目又恢復移動前的排列位置。
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
// Step 2-2
final int fromPos = viewHolder.getAdapterPosition();
final int toPos = target.getAdapterPosition();
// move item in `fromPos` to `toPos` in adapter.
adapter.moveItem(fromPos, toPos);
return true;// true if moved, false otherwise
}
moveItem()的實作如下,items是範例中的資料Model,型態是List,在此我用Collections.swap()做個簡單的項目交換, 接著一樣用notifyItemRemoved()更新畫面。
// Step 2-2
public void moveItem(int fromPos, int toPos) {
Collections.swap(items, fromPos, toPos);
adapter.notifyItemMoved(fromPos, toPos);
}
Swipe之後的動畫效果與資料更新
在此範例中,我們以刪除作為swipe時要執行的目標動作, 首先,在onSwiped的函式中加入以下程式碼,就能讓列表有其他項目自動上移的效果, 主要作法是透過viewHolder取得目前swipe的項目位置,然後利用Adapter內建的notifyItemRemoved(int position)通知列表畫面更新。@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// Step 3-1
int position = viewHolder.getAdapterPosition();
adapter.notifyItemRemoved(position);
}
效果如下:
同上下拖拉一樣,目前的程式碼也只是讓畫面有效果,但還沒有連同資料model一起更新,所以會發現畫面上的列表下方好像怪怪的。 所以需要再調整成如下的程式碼,在此我將刪除項目的動作放在自行實作的Adapter的public函式removeItem()
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// Step 3-2
int position = viewHolder.getAdapterPosition();
adapter.removeItem(position);
}
removeItem()的實作如下,主要內容是從model中移除指定的項目並通知畫面更新。
// Step 3-2
public void removeItem(int position) {
items.remove(position);
adapter.notifyItemRemoved(position);
}
留言
張貼留言