[Android] Drag & Drop, Swipe to dissmiss Recyclerview
Chắc hẳn các bạn đã nhìn thấy hoặc sử dụng rất nhiều thư viện cho phép kéo thả (dra g& drop) hay vuốt để xóa item (swipe to dismiss) của RecyclerView. Có bao giờ các bạn tự hỏi làm sao để chúng có thể kéo thả mượn mà, đẹp mắt như vậy không? Trong bài viết này chúng ta sẽ cùng tìm hiểu cách làm 1 Recyclerview như vậy nhé.
Ví dụ về Drag & Drop, Swipe to dissmiss RecyclerView
1. Tìm hiểu ItemTouchHelper.Callback
Về cơ bản thì ItemTouchHelper.Callback là một abstract class, cung cấp 3 abstract menthod chính là:
1.1. getMovementFlags
getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder);
Trả về giá trị là một số nguyên, định nghĩa cờ cho phép di chuyển item ở mỗi state. Default là ACTION_STATE_IDLE = 0 - Không cho phép drag & drop.
Bạn có thể trả về flag thông qua 2 method chính mà ItemTouchHelper cung cấp là makeMovementFlags(int, int) và makeFlag(int, int)
Ở ví dụ của mình mình đã sử dụng menthod makeMovementFlags
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlag = ItemTouchHelper.LEFT;
return makeMovementFlags(dragFlag, swipeFlag);
}
Ở đây mình cho phép người dùng có thể Drag Lên và xuống, và cho phép người dùng vuốt sang trái để dissmiss. Nếu muốn cho phép người dùng vuốt sang phải để dissmiss thì mình khai báo ItemTouchHelper.RIGHT còn muốn cả trái và phải thì sử dụng ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT
1.2. onMove
onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
Menthod này được gọi khi người dùng kéo 1 item từ vị trí này đến vị trí khác.
- viewHolder là viewHolder của Item hiện tại đang được kéo
- target là viewHolder của item đang được kéo tới. Bạn có thể dễ dàng xác định vị trí của 2 item này bằng cách sử dụng menthod getAdapterPosition của ViewHolder.
3. onSwiped
onSwiped(RecyclerView.ViewHolder viewHolder, int direction)
Trả về khi một item của recyclerview bị biến mất khi swipe.
- viewHolder là ViewHolder của item vừa dissmiss
- direction là hướng dissmiss của item, có 2 kiểu dissmiss là START - Phải qua trái và END - Trái qua phải.
2. Tạo interface lắng nghe sự kiện drag & drop, swipe : ItemTouchListenner
Để dễ dàng bắt được sự kiện swipe và drag & drop, chúng ta tạo ra 1 listenner để lắng nghe các event đó
ItemTouchListenner.java
public interface ItemTouchListenner {
void onMove(int oldPosition, int newPosition);
void swipe(int position, int direction);
}
3. Gắn sự kiện drag & drop trong ItemTouchHelper.Callback
Chúng ta sẽ custom class ItemTouchHelper.Callback để nhận sự kiện swipe và drag & drop
SimpleItemToucHelperCallback.java
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
private ItemTouchListenner mListenner;
public SimpleItemTouchHelperCallback(ItemTouchListenner mListenner) {
this.mListenner = mListenner;
}
@Override
public boolean isLongPressDragEnabled() {
return super.isLongPressDragEnabled();
}
@Override
public boolean isItemViewSwipeEnabled() {
return super.isItemViewSwipeEnabled();
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
return makeMovementFlags(dragFlag, swipeFlag);
}
@Override
public boolean onMove(RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
mListenner.onMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mListenner.swipe(viewHolder.getAdapterPosition(), direction);
}
}
Như vậy là mỗi khi người dùng kéo thả hoặc vuốt thì mListenner sẽ báo về cho chúng ta thông qua 2 menthod swipe và onMove chúng ta chỉ cần update lai adapter khi có sự thay đổi về dữ liệu là được rất đơn giản phải không nào?
4. Gắn ItemTouchHelper cho Recyclerview
Để gắn ItemToucherHelper chúng ta sử dụng menthod attackToRecyclerView(RecyclerView view) của lớp ItemTouchHelper
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(new ItemTouchListenner() {
@Override
public void onMove(int oldPosition, int newPosition) {
mAdapter.onMove(oldPosition, newPosition);
}
@Override
public void swipe(int position, int direction) {
mAdapter.swipe(position, direction);
}
});
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(recyclerView);
Như vậy mỗi khi có sự kiện move và swipe ta sẽ gọi tới menthod update giao diện của adapter.
5. Update lại adapter của RecyclerView khi có sự kiện thay đổi
Trong lớp adapter ta định nghĩa thêm 2 menthod để xử lý sự kiện là onMove và swipe. Đổi chỗ vị trí các item khi drag & drop
public void onMove(int fromPosition, int toPosition) {
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(mData, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(mData, i, i - 1);
}
}
notifyItemMoved(fromPosition, toPosition);
}
Xóa item khi swipe thành công:
public void swipe(int position, int direction) {
mData.remove(position);
notifyItemRemoved(position);
}
Trên đây là phần giới thiệu của mình về Swipe, Drag & Drop trong RecyclerView, rất mong sẽ giúp ích được cho các dự án của các bạn.
Cảm ơn các bạn đã đọc bài viết.
Chào thân ái và quyết thắng!
Theo dõi VnCoder trên Facebook, để cập nhật những bài viết, tin tức và khoá học mới nhất!