
Ada banyak tutorial, pustaka, dan implementasi seret & lepas dan geser ke untuk mengabaikan di Android menggunakan RecyclerView. Sebagian besar dari mereka masih menggunakan View.OnDragListener yang sudah usang dan pendekatan SwipeToDismiss yang dikembangkan oleh Roman Nurik. Meskipun metode baru dan lebih efektif sudah tersedia. Sangat sedikit yang menggunakan API terbaru, sering mengandalkan GestureDetectors
dan onInterceptTouchEvent
atau implementasi lebih kompleks lainnya. Sebenarnya, ada cara yang sangat sederhana untuk menambahkan fungsi-fungsi ini ke RecyclerView
. Ini hanya membutuhkan satu kelas, yang juga merupakan bagian dari Perpustakaan Dukungan Android.
ItemTouchHelper
ItemTouchHelper adalah utilitas tangguh yang menangani semua yang perlu Anda lakukan untuk menambahkan fungsi seret & lepas dan gesek ke abaikan ke RecyclerView
. Utilitas ini adalah subkelas dari RecyclerView.ItemDecoration , membuatnya mudah untuk ditambahkan ke hampir semua LayoutManager
dan adaptor yang ada. Ini juga bekerja dengan animasi elemen dan menyediakan kemampuan untuk menarik dan melepas elemen dari satu jenis ke tempat lain dalam daftar dan banyak lagi. Pada artikel ini, saya akan menunjukkan implementasi sederhana dari ItemTouchHelper
. Nantinya, sebagai bagian dari seri artikel ini, kami akan memperluas cakupan dan mempertimbangkan opsi lain.
Catatan Ingin melihat hasilnya segera? Lihat Github: Android-ItemTouchHelper-Demo . Komit pertama berkaitan dengan artikel ini. File demo .apk
dapat diunduh di sini .

Kustomisasi
Pertama, kita perlu mengkonfigurasi RecyclerView
. Jika Anda belum melakukannya, tambahkan ketergantungan RecyclerView
ke file build.gradle
Anda.
compile 'com.android.support:recyclerview-v7:22.2.0'
ItemTouchHelper
akan bekerja dengan hampir semua RecyclerView.Adapter
dan LayoutManager
, tetapi artikel ini didasarkan pada contoh menggunakan file-file ini .
Menggunakan ItemTouchHelper dan ItemTouchHelper.Callback
Untuk menggunakan ItemTouchHelper
, Anda harus membuat ItemTouchHelper.Callback . Ini adalah antarmuka yang memungkinkan Anda melacak tindakan gerakan ( eng. Move) dan swipe ( eng. Swipe). Selain itu, di sini Anda dapat mengontrol status komponen view
dipilih dan mengganti animasi default. Ada kelas pembantu yang bisa Anda gunakan jika Anda ingin menggunakan implementasi dasar, SimpleCallback . Tetapi untuk memahami bagaimana ini bekerja dalam praktiknya, kami akan melakukan semuanya sendiri.
Fungsi utama antarmuka yang harus kita definisikan ulang untuk memasukkan fungsionalitas dasar drag & drop dan swipe-to-dismiss :
getMovementFlags(RecyclerView, ViewHolder) onMove(RecyclerView, ViewHolder, ViewHolder) onSwiped(ViewHolder, int)
Kami juga akan menggunakan beberapa metode pembantu:
isLongPressDragEnabled() isItemViewSwipeEnabled()
Mari kita pertimbangkan satu per satu.
@Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); }
ItemTouchHelper
memudahkan untuk menentukan arah suatu acara. Anda perlu mengganti metode getMovementFlags()
untuk menunjukkan arah mana yang akan didukung dan diseret. Untuk membuat flag kembali, gunakan metode helper ItemTouchHelper.makeMovementFlags(int, int)
. Dalam contoh ini, kami mengizinkan seret dan lepas di kedua arah.
@Override public boolean isLongPressDragEnabled() { return true; }
ItemTouchHelper
hanya dapat digunakan untuk drag and drop tanpa fungsi swipe (atau sebaliknya), jadi Anda harus menentukan dengan tepat fitur mana yang harus didukung. Metode isLongPressDragEnabled()
harus mengembalikan true
untuk mendukung drag and drop setelah mengklik panjang pada elemen RecyclerView
. Atau, Anda dapat memanggil metode ItemTouchHelper.startDrag(RecyclerView.ViewHolder)
untuk mulai menyeret secara manual. Kami akan mempertimbangkan opsi ini nanti.
@Override public boolean isItemViewSwipeEnabled() { return true; }
Untuk mengaktifkan mencambuk setelah menyentuh di mana saja dalam komponen view
, cukup kembalikan true
dari metode isItemViewSwipeEnabled()
. Atau, Anda dapat memanggil metode ItemTouchHelper.startSwipe(RecyclerView.ViewHolder)
untuk memulai gesek secara manual.
Dua metode berikut ini, onMove()
dan onSwiped()
, diperlukan untuk memberi tahu Anda tentang pembaruan data. Jadi, pertama-tama kita akan membuat antarmuka yang memungkinkan acara-acara ini diteruskan di sepanjang rantai panggilan.
ItemTouchHelperAdapter.java
public interface ItemTouchHelperAdapter { void onItemMove(int fromPosition, int toPosition); void onItemDismiss(int position); }
Cara termudah untuk melakukan ini adalah memiliki RecyclerListAdapter mengimplementasikan pendengar.
public class RecyclerListAdapter extends RecyclerView.Adapter<ItemViewHolder> implements ItemTouchHelperAdapter {
Sangat penting untuk memanggil metode notifyItemRemoved()
dan notifyItemMoved()
sehingga adaptor melihat perubahannya. Perlu juga dicatat bahwa kita mengubah posisi elemen setiap kali komponen view
bergeser ke indeks baru, dan tidak di akhir gerakan (peristiwa "drop") .
Sekarang kita dapat kembali membuat SimpleItemTouchHelperCallback
, karena kita masih perlu mengganti metode onMove()
dan onSwiped()
. Pertama-tama tambahkan konstruktor dan bidang untuk adaptor:
private final ItemTouchHelperAdapter mAdapter; public SimpleItemTouchHelperCallback( ItemTouchHelperAdapter adapter) { mAdapter = adapter; }
Kemudian definisikan kembali acara yang tersisa dan laporkan ini ke adaptor:
@Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); }
Akibatnya, kelas Callback
akan terlihat seperti ini:
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { private final ItemTouchHelperAdapter mAdapter; public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) { mAdapter = adapter; } @Override public boolean isLongPressDragEnabled() { return true; } @Override public boolean isItemViewSwipeEnabled() { return true; } @Override public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); } @Override public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) { mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; } @Override public void onSwiped(ViewHolder viewHolder, int direction) { mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); } }
Ketika Callback siap, kita dapat membuat ItemTouchHelper
dan memanggil metode attachToRecyclerView(RecyclerView)
(misalnya, di MainFragment.java ):
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter); ItemTouchHelper touchHelper = new ItemTouchHelper(callback); touchHelper.attachToRecyclerView(recyclerView);
Setelah memulai, Anda harus mendapatkan sesuatu seperti berikut:

Kesimpulan
Ini adalah implementasi ItemTouchHelper
paling disederhanakan. Namun, Anda mungkin memperhatikan bahwa Anda tidak harus menggunakan pustaka pihak ketiga untuk mengimplementasikan tindakan seret & lepaskan standar dan gesek-ke-abaikan di RecyclerView
. Di bagian selanjutnya, kita akan lebih memperhatikan penampilan elemen pada saat drag and drop.
Kode sumber
Saya membuat proyek di GitHub untuk menunjukkan apa yang tercakup dalam seri artikel ini: Android-ItemTouchHelper-Demo . Komit pertama terutama berkaitan dengan bagian ini dan sedikit ke yang kedua .
→ Seret dan Gesek di RecyclerView. Bagian 2: pengontrol seret dan lepas, kisi, dan animasi khusus