Ziehen und wischen Sie in RecyclerView. Teil 1: ItemTouchHelper

Ziehen und wischen Sie in RecyclerView. Teil 1: ItemTouchHelper


Es gibt viele Tutorials, Bibliotheken sowie Drag & Drop- und Swipe-to-Dism-Implementierungen in Android mit RecyclerView. Die meisten von ihnen verwenden immer noch den veralteten View.OnDragListener und den von Roman Nurik entwickelten SwipeToDismiss- Ansatz. Obwohl bereits neue und effektivere Methoden verfügbar sind. Nur sehr wenige verwenden die neuesten APIs und onInterceptTouchEvent häufig auf GestureDetectors und onInterceptTouchEvent oder andere komplexere Implementierungen. Tatsächlich gibt es eine sehr einfache Möglichkeit, diese Funktionen zu RecyclerView hinzuzufügen. Dies erfordert nur eine Klasse, die ebenfalls Teil der Android Support Library ist.


ItemTouchHelper


ItemTouchHelper ist ein leistungsstarkes Dienstprogramm, das sich um alles kümmert, was Sie tun müssen, um RecyclerView Drag & Drop- und Swipe-to-Dism-Funktionen hinzuzufügen. Dieses Dienstprogramm ist eine Unterklasse von RecyclerView.ItemDecoration , mit der sich fast jeder vorhandene LayoutManager und Adapter problemlos hinzufügen lässt. Es funktioniert auch mit Elementanimationen und bietet die Möglichkeit, Elemente eines Typs an eine andere Stelle in der Liste zu ziehen und dort abzulegen. In diesem Artikel werde ich eine einfache Implementierung von ItemTouchHelper . Später, als Teil dieser Artikelserie, werden wir den Umfang erweitern und andere Optionen in Betracht ziehen.


Hinweis Möchten Sie das Ergebnis sofort sehen? Schauen Sie sich Github an: Android-ItemTouchHelper-Demo . Das erste Commit bezieht sich auf diesen Artikel. Demo .apk Datei kann hier heruntergeladen werden .


Beispiel


Anpassung


Zuerst müssen wir die RecyclerView konfigurieren. Wenn Sie dies noch nicht getan haben, fügen Sie die RecyclerView Abhängigkeit zu Ihrer build.gradle Datei hinzu.


 compile 'com.android.support:recyclerview-v7:22.2.0' 

ItemTouchHelper funktioniert mit fast jedem RecyclerView.Adapter und LayoutManager . Dieser Artikel basiert jedoch auf Beispielen, die diese Dateien verwenden .


Verwenden von ItemTouchHelper und ItemTouchHelper.Callback


Um ItemTouchHelper verwenden zu ItemTouchHelper , müssen Sie einen ItemTouchHelper.Callback erstellen. Dies ist eine Schnittstelle, über die Sie die Aktionen von Bewegung ( dt. Bewegen) und Wischen ( dt. Wischen) verfolgen können. Außerdem können Sie hier den Status der ausgewählten view steuern und die Standardanimation überschreiben. Es gibt eine Hilfsklasse , die Sie verwenden können, wenn Sie die Basisimplementierung SimpleCallback verwenden möchten . Aber um zu verstehen, wie dies in der Praxis funktioniert, werden wir alles selbst machen.


Die Hauptfunktionen der Benutzeroberfläche, die wir neu definieren müssen, um die Grundfunktionen von Drag & Drop und Swipe-to-Dism einzuschließen :


 getMovementFlags(RecyclerView, ViewHolder) onMove(RecyclerView, ViewHolder, ViewHolder) onSwiped(ViewHolder, int) 

Wir werden auch verschiedene Hilfsmethoden verwenden:


 isLongPressDragEnabled() isItemViewSwipeEnabled() 

Betrachten wir sie einzeln.


 @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 Sie leicht die Richtung eines Ereignisses bestimmen. Sie müssen die Methode getMovementFlags() überschreiben, um anzugeben, welche Richtungen zum Ziehen und Ablegen unterstützt werden. Verwenden Sie zum Erstellen von Rückgabeflags die ItemTouchHelper.makeMovementFlags(int, int) . In diesem Beispiel erlauben wir Drag & Drop in beide Richtungen.


 @Override public boolean isLongPressDragEnabled() { return true; } 

ItemTouchHelper kann nur zum Ziehen und Ablegen ohne Wischfunktion verwendet werden (oder umgekehrt). Sie müssen daher genau angeben, welche Funktionen unterstützt werden sollen. Die Methode isLongPressDragEnabled() muss true , um Drag & Drop nach einem langen Klick auf das RecyclerView Element zu unterstützen. Alternativ können Sie die ItemTouchHelper.startDrag(RecyclerView.ViewHolder) Methode ItemTouchHelper.startDrag(RecyclerView.ViewHolder) aufrufen, um das Ziehen manuell zu starten. Wir werden diese Option später prüfen.


 @Override public boolean isItemViewSwipeEnabled() { return true; } 

Um das Auspeitschen nach dem Berühren einer beliebigen Stelle in der view zu aktivieren, geben Sie einfach true von der Methode isItemViewSwipeEnabled() . Alternativ können Sie die ItemTouchHelper.startSwipe(RecyclerView.ViewHolder) Methode ItemTouchHelper.startSwipe(RecyclerView.ViewHolder) aufrufen, um das ItemTouchHelper.startSwipe(RecyclerView.ViewHolder) manuell zu starten.


Die folgenden beiden Methoden, onMove() und onSwiped() , sind erforderlich, um Sie über onSwiped() zu informieren. Zuerst erstellen wir eine Schnittstelle, über die diese Ereignisse entlang der Aufrufkette weitergeleitet werden können.


ItemTouchHelperAdapter.java


 public interface ItemTouchHelperAdapter { void onItemMove(int fromPosition, int toPosition); void onItemDismiss(int position); } 

Der einfachste Weg, dies zu tun, besteht darin, den Listener vom RecyclerListAdapter implementieren zu lassen.


 public class RecyclerListAdapter extends RecyclerView.Adapter<ItemViewHolder> implements ItemTouchHelperAdapter { // ...   [](https://gist.github.com/iPaulPro/2216ea5e14818056cfcc#file-recyclerlistadapter-java) @Override public void onItemDismiss(int position) { mItems.remove(position); notifyItemRemoved(position); } @Override public boolean onItemMove(int fromPosition, int toPosition) { if (fromPosition < toPosition) { for (int i = fromPosition; i < toPosition; i++) { Collections.swap(mItems, i, i + 1); } } else { for (int i = fromPosition; i > toPosition; i--) { Collections.swap(mItems, i, i - 1); } } notifyItemMoved(fromPosition, toPosition); return true; } 

Es ist sehr wichtig, die notifyItemRemoved() und notifyItemMoved() , damit der Adapter die Änderungen sieht. Es sollte auch beachtet werden, dass wir die Position des Elements jedes Mal ändern, wenn die view auf einen neuen Index verschoben wird, und nicht ganz am Ende der Bewegung (das "Drop" -Ereignis) .


Jetzt können wir wieder SimpleItemTouchHelperCallback , da wir die onMove() und onSwiped() noch überschreiben onMove() . Fügen Sie zuerst den Konstruktor und das Feld für den Adapter hinzu:


 private final ItemTouchHelperAdapter mAdapter; public SimpleItemTouchHelperCallback( ItemTouchHelperAdapter adapter) { mAdapter = adapter; } 

Definieren Sie dann die verbleibenden Ereignisse neu und melden Sie dies dem Adapter:


 @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()); } 

Daher sollte die Callback Klasse Callback so aussehen:


 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()); } } 

Wenn Callback bereit ist, können wir einen ItemTouchHelper erstellen und die Methode attachToRecyclerView(RecyclerView) aufrufen (z. B. in MainFragment.java ):


 ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter); ItemTouchHelper touchHelper = new ItemTouchHelper(callback); touchHelper.attachToRecyclerView(recyclerView); 

Nach dem Start sollten Sie Folgendes erhalten:


Ergebnis


Fazit


Dies ist die ItemTouchHelper Implementierung von ItemTouchHelper . Möglicherweise stellen Sie jedoch fest, dass Sie keine Bibliothek eines Drittanbieters verwenden müssen, um die standardmäßigen Drag & Drop- und Swipe-to-Dism-Aktionen in RecyclerView zu implementieren. Im nächsten Teil werden wir dem Erscheinungsbild der Elemente zum Zeitpunkt des Drag & Drop mehr Aufmerksamkeit schenken.


Quellcode


Ich habe auf GitHub ein Projekt erstellt, um zu demonstrieren, was in dieser Artikelserie behandelt wird: Android-ItemTouchHelper-Demo . Das erste Commit bezieht sich hauptsächlich auf diesen Teil und ein bisschen auf das zweite .


→ Ziehen und wischen Sie in RecyclerView. Teil 2: Drag & Drop-Controller, Raster und benutzerdefinierte Animationen

Source: https://habr.com/ru/post/de427681/


All Articles