
Im ersten Teil haben wir uns mit ItemTouchHelper und der Implementierung von ItemTouchHelper.Callback befasst , mit dem RecyclerView
die grundlegenden Drag & Drop- und Swipe-to- Discharge -Funktionen RecyclerView
. In diesem Artikel werden wir die vorherigen Schritte fortsetzen, indem wir Unterstützung für das Anordnen von Elementen in Form eines Rasters, Drag & Drop-Controllern, die Auswahl eines Listenelements und benutzerdefinierte Wischanimationen hinzufügen.

Drag & Drop-Controller
Beim Erstellen einer Liste, die Drag & Drop unterstützt , wird normalerweise die Möglichkeit implementiert, Elemente per Touch per Drag & Drop zu verschieben . Dies trägt zur Klarheit und Benutzerfreundlichkeit der Liste im "Bearbeitungsmodus" bei und wird auch von Materialrichtlinien empfohlen. Das Hinzufügen von Drag & Drop-Controllern zu unserem Beispiel ist unglaublich einfach.

Aktualisieren Sie zunächst das layout
Elements ( item_main.xml ).
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/item" android:layout_width="match_parent" android:layout_height="?listPreferredItemHeight" android:clickable="true" android:focusable="true" android:foreground="?selectableItemBackground"> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="16dp" android:textAppearance="?android:attr/textAppearanceMedium" /> <ImageView android:id="@+id/handle" android:layout_width="?listPreferredItemHeight" android:layout_height="match_parent" android:layout_gravity="center_vertical|right" android:scaleType="center" android:src="@drawable/ic_reorder_grey_500_24dp" /> </FrameLayout>
Das für den Drag Controller verwendete Bild befindet sich in den Material Design-Symbolen und wird mithilfe des praktischen Symbolgenerator-Plugins in Android Studio zum Projekt hinzugefügt.
Wie in einem vorherigen Artikel kurz erwähnt, können Sie mit ItemTouchHelper.startDrag(ViewHolder)
programmgesteuert ein Drag & Drop starten. Wir müssen also nur den ViewHolder
aktualisieren, indem wir einen Drag-Controller hinzufügen und einen einfachen Touch-Handler einrichten, der startDrag()
.
Wir benötigen eine Schnittstelle, um Ereignisse entlang der Kette zu übertragen:
public interface OnStartDragListener { void onStartDrag(RecyclerView.ViewHolder viewHolder); }
Definieren Sie dann im ImageView
eine ImageView
für den Drag Controller:
public final ImageView handleView; public ItemViewHolder(View itemView) { super(itemView);
und aktualisieren Sie den RecyclerListAdapter
:
private final OnStartDragListener mDragStartListener; public RecyclerListAdapter(OnStartDragListener dragStartListener) { mDragStartListener = dragStartListener;
RecyclerListAdapter
sollte jetzt RecyclerListAdapter
so aussehen.
Sie müssen OnStartDragListener
den OnStartDragListener
zum Fragment hinzufügen:
public class RecyclerListFragment extends Fragment implements OnStartDragListener {
RecyclerListFragment
sollte jetzt so aussehen. Wenn Sie jetzt die Anwendung starten, können Sie mit dem Ziehen und Ablegen beginnen, indem Sie den Controller berühren.

Markieren eines Listenelements
In unserem Beispiel gibt es keine visuelle Anzeige für das zu ziehende Objekt. Natürlich sollte dies nicht sein, aber es ist leicht zu beheben. Mit ItemTouchHelper
Sie Standard-Effekte zur Hervorhebung von ItemTouchHelper
verwenden. Bei Lollipop und späteren Versionen von Android „verteilt“ sich die Hintergrundbeleuchtung während der Interaktion mit dem Element. In früheren Versionen ändert das Element einfach seine Farbe in abgedunkelt.
Um dies in unserem Beispiel zu implementieren, fügen Sie einfach einen Hintergrund ( background
Eigenschaft) zum Stamm- FrameLayout
Elements FrameLayout
oder legen Sie ihn im Konstruktor RecyclerListAdapter.ItemViewHolder fest . Es wird ungefähr so aussehen:

Es sieht cool aus, aber vielleicht möchten Sie noch mehr kontrollieren. Eine Möglichkeit, dies zu tun, besteht darin, ViewHolder
erlauben, ViewHolder
eines Elements zu verarbeiten. Zu diesem ItemTouchHelper.Callback
bietet ItemTouchHelper.Callback
zwei weitere Methoden:
onSelectedChanged(ViewHolder, int)
wird jedes Mal aufgerufen, wenn sich der Status eines Elements in Drag ( ACTION_STATE_DRAG ) oder Swipe ( ACTION_STATE_SWIPE ) ändert . Dies ist ein idealer Ort, um den Status der view
in aktiv zu ändern.clearView(RecyclerView, ViewHolder)
wird aufgerufen, wenn die Drag & Drop- view
abgeschlossen ist und auch wenn das Wischen abgeschlossen ist ( ACTION_STATE_IDLE ). Hier wird normalerweise der Ausgangszustand Ihrer view
wiederhergestellt.
Lassen Sie uns jetzt einfach alles zusammenfügen.
Erstellen Sie zunächst eine Schnittstelle, die ViewHolders
implementiert:
public interface ItemTouchHelperViewHolder { void onItemSelected(); void onItemClear(); }
Implementieren Sie dann im SimpleItemTouchHelperCallback
die entsprechenden Methoden:
@Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
Jetzt muss nur noch RecyclerListAdapter.ItemViewHolder
ItemTouchHelperViewHolder
implementieren:
public class ItemViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
In diesem Beispiel fügen wir einfach einen grauen Hintergrund hinzu, während das Element aktiv ist, und entfernen ihn dann. Wenn Ihr ItemTouchHelper
und Ihr Adapter eng miteinander verbunden sind, können Sie diese Einstellung einfach aufgeben und den Status der view
direkt in ItemTouchHelper.Callback
.
Netze
Wenn Sie jetzt versuchen, den GridLayoutManager
, werden Sie GridLayoutManager
, dass er nicht richtig funktioniert. Der Grund und die Lösung sind einfach: Wir müssen unserem ItemTouchHelper
dass wir das Ziehen von Elementen nach links und rechts unterstützen möchten. Zuvor in SimpleItemTouchHelperCallback
wir bereits SimpleItemTouchHelperCallback
angegeben:
@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); }
Die einzige Änderung, die zur Unterstützung der Gitter erforderlich ist, besteht darin, die entsprechenden Flags hinzuzufügen:
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
Swipe-to-Dism ist jedoch kein sehr natürliches Verhalten für swipeFlags
, sodass swipeFlags
höchstwahrscheinlich swipeFlags
:
@Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; int swipeFlags = 0; return makeMovementFlags(dragFlags, swipeFlags); }
GridLayoutManager
Beispiel für ein funktionierendes GridLayoutManager
finden Sie unter RecyclerGridFragment . So sieht es beim Start aus:

Benutzerdefinierte Swipe-Animationen
ItemTouchHelper.Callback
bietet eine sehr bequeme Möglichkeit, die Animation beim Ziehen oder Fegen vollständig zu steuern. Da ItemTouchHelper
ein RecyclerView.ItemDecoration ist , können wir auf ähnliche Weise in das Rendern einer view
eingreifen. Im nächsten Teil werden wir diese Frage genauer untersuchen. Schauen wir uns zunächst ein einfaches Beispiel für das Überschreiben der Standard-Wischanimation an, um ein lineares Verschwinden anzuzeigen.
@Override public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { float width = (float) viewHolder.itemView.getWidth(); float alpha = 1.0f - Math.abs(dX) / width; viewHolder.itemView.setAlpha(alpha); viewHolder.itemView.setTranslationX(dX); } else { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } }
Die dY
dX
und dY
sind die aktuelle Verschiebung relativ zur ausgewählten view
, wobei:
- -1.0f ist ein vollständiger Wisch von rechts nach links (von
ItemTouchHelper.END
zu ItemTouchHelper.START
) - 1.0f wird vollständig von links nach rechts
ItemTouchHelper.START
(von ItemTouchHelper.START
zu ItemTouchHelper.END
)
Es ist wichtig, super
für jeden actionState
, den Sie nicht verarbeiten, um die Standardanimation auszulösen.
Im nächsten Teil betrachten wir ein Beispiel, in dem wir das Zeichnen eines Elements im Moment des Drag & Drop steuern.
Fazit
Tatsächlich macht das Einrichten von ItemTouchHelper ziemlich viel Spaß. Um das Volumen dieses Artikels nicht zu erhöhen, habe ich ihn in mehrere unterteilt.
Quellcode
Den vollständigen Code für diese Artikelserie finden Sie in den GitHub-Repositorys von Android-ItemTouchHelper-Demo . Dieser Artikel behandelt Commits von ef8f149 bis d164fba .
← Ziehen und Wischen in RecyclerView. Teil 1: ItemTouchHelper