接續上一遍, 這次要講的是相對進階的操作:
效果圖:
要實現拖曳, 需要重寫onMove
方法。
public ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
...
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getBindingAdapterPosition();
int toPosition = target.getBindingAdapterPosition();
Collections.swap(dataList, fromPosition, toPosition); //Item互換
notifyItemMoved(fromPosition, toPosition); //通知Recyclerview Item被移動了
return false;
}
...
}
new ItemTouchHelper.SimpleCallback(dragDirs
, swipeDirs
)
需要傳入兩個參數:
dragDirs
:表示可以拖曳的方向swipeDirs
:表示可以滑動的方向ItemTouchHelper.UP
ItemTouchHelper.DOWN
ItemTouchHelper.LEFT
ItemTouchHelper.RIGHT
效果圖:
要實現滑動,需要重寫onSwiped
方法。
private List<String> archivedItems = new ArrayList<>(); // 用來紀錄右滑被封存的Item清單
public ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
...
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getBindingAdapterPosition();
switch (direction) {
// Item向左滑表示刪除
case ItemTouchHelper.LEFT:
dataList.remove(position);
notifyItemRemoved(position); // 通知RecyclerView有Item被刪除了, 用以更新畫面
break;
// Item向右滑表示封存
case ItemTouchHelper.RIGHT:
String itemName = dataList.get(position);
archivedItems.add(itemName);
dataList.remove(position);
notifyItemRemoved(position); // 通知RecyclerView有Item被刪除了, 用以更新畫面
break;
}
}
}
在github上有位大神已經實現這樣的效果並提供簡單的API供使用,我們只需要把這個第三方套件導入自己的專案即可。跟著以下的步驟配置環境:
套件連結:https://github.com/xabaras/RecyclerViewSwipeDecorator
settings.gradle
添加dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
...
maven { url 'https://jitpack.io' }
}
}
build.gradle(Module: app)
添加依賴dependencies {
...
implementation 'com.github.xabaras:RecyclerViewSwipeDecorator:1.4'
}
onChildDraw
來實現在滑動時, item後面呈現圖示的效果public ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
...
@Override
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
new RecyclerViewSwipeDecorator.Builder(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
.addSwipeLeftBackgroundColor(ContextCompat.getColor(viewHolder.itemView.getContext(), R.color.item_delete))
.addSwipeLeftActionIcon(R.drawable.ic_delete_24dp)
.addSwipeRightBackgroundColor(ContextCompat.getColor(viewHolder.itemView.getContext(), R.color.item_archive))
.addSwipeRightActionIcon(R.drawable.ic_archive_24dp)
.create()
.decorate();
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
private String deletedItem = null; // 用來記錄左滑刪除的Item
private List<String> archivedItems = new ArrayList<>(); // 用來紀錄右滑被封存的Item清單
public ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
...
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getBindingAdapterPosition(); // 紀錄當前滑動的item位置
switch (direction) {
// Item向左滑表示刪除
case ItemTouchHelper.LEFT:
deletedItem = dataList.get(position);
dataList.remove(position);
notifyItemRemoved(position);
// 復原操作提示
Snackbar.make(viewHolder.itemView, deletedItem + " 已被刪除", Snackbar.LENGTH_LONG)
.setAction("復原", (view) -> {
dataList.add(position, deletedItem);
notifyItemInserted(position);
}
).show();
break;
// Item向右滑表示封存
case ItemTouchHelper.RIGHT:
String itemName = dataList.get(position);
archivedItems.add(itemName);
dataList.remove(position);
notifyItemRemoved(position);
// 復原操作提示
Snackbar.make(viewHolder.itemView, itemName + " 已被封存", Snackbar.LENGTH_LONG)
.setAction("復原", (view) -> {
dataList.add(position, itemName);
archivedItems.remove(archivedItems.indexOf(itemName));
notifyItemInserted(position);
}
).show();
break;
}
}
...
}