Android RecyclerView ItemTouchHelper Swipe rückgängig machen und Ansichtshalter wiederherstellen

Lesezeit: 6 Minuten

Benutzer-Avatar
Kukabi

Gibt es eine Möglichkeit, eine Wischaktion rückgängig zu machen und den Ansichtshalter in seine ursprüngliche Position zurückzusetzen nach der Schlag ist abgeschlossen und onSwiped heißt auf der ItemTouchHelper.Callback Beispiel? ich habe das RecyclerView, ItemTouchHelper und ItemTouchHelper.Callback Instanzen perfekt zusammenarbeiten, muss ich nur die Swipe-Aktion rückgängig machen und nicht Entfernen Sie in einigen Fällen das geklaute Element.

  • Hast du darauf eine Antwort?

    – Maveroid

    6. August 2015 um 10:53 Uhr

  • @maveroid ja, siehe unten.

    – kukabi

    7. August 2015 um 7:51 Uhr

Nach einigem Hin und Her habe ich eine Lösung gefunden. Anruf notifyItemChanged auf Ihrem Adapter. Dadurch wird die herausgezogene Ansicht wieder in ihre ursprüngliche Position animiert.

  • Funktioniert die meiste Zeit, aber es gibt Zeiten, in denen dies nicht funktioniert.

    – Jaga

    12. November 2015 um 8:41 Uhr

  • Es funktioniert, aber ich habe ein Problem. Wenn ich “notifyItemChanged” aufrufe, erzeugt es einen “Blitz” in der Ansicht. Gibt es eine Möglichkeit, diesen “Flash” @DariusL zu überspringen?

    – RobertV

    15. November 2016 um 8:27 Uhr


  • Dies spielt für mich eine Fade-Animation anstelle einer Übersetzungsanimation ab.

    – Sake

    26. Mai 2017 um 2:54 Uhr

  • Dies könnte eine sehr späte Antwort sein. Aber ich versuche seit fast 2 Tagen, die Bounce-Back-Animation zu machen. Das ist die beste Lösung, die ich bisher gefunden habe.

    – CodeAndWave

    27. Juni 2017 um 8:06 Uhr

  • Ich mag diese Lösung wirklich nicht, weil sie nicht sanft, sondern heftig in ihre Position zurückkehrt …

    – Vucko

    7. April 2020 um 19:04 Uhr

Sie sollten überschreiben onSwiped Methode ein ItemTouchHelper.Callback und aktualisieren Sie dieses bestimmte Element.

 @Override
 public void onSwiped(RecyclerView.ViewHolder viewHolder,
     int direction) {
     adapter.notifyItemChanged(viewHolder.getAdapterPosition());
 }

  • Ich habe vor dem Unterdrücken eine Bestätigung angefordert, mit der Möglichkeit, abzubrechen. Nachdem ich die obigen Lösungen gesucht und ausprobiert hatte, war es nicht wirklich zufrieden, also habe ich Ihre ausprobiert. Dann habe ich gesehen, dass ich genau das getan habe, was Sie in meinem Code als parametrisierten Rückruf gesagt haben … Und das Problem war, dass ich die Rückrufmethode NICHT auf “false” aufgerufen habe, um diesen Teil des Codes zu aktivieren. Damit hast du mich gerettet.

    – Feubi

    24. August 2018 um 19:06 Uhr

  • Ich musste die Aktualisierungsempfehlung von @ jimmy0251 oben von einer Fragment-Methode ausführen, da mein onSwiped() die Hintergrundfarbe ändert. Lief wie am Schnürchen!

    – AJW

    2. Juni 2019 um 21:40 Uhr

Googles ItemTouchHelper Die Umsetzung setzt dies voraus jeder Ausgelesene Elemente werden schließlich aus der Recycler-Ansicht entfernt, während dies in einigen Anwendungen möglicherweise nicht der Fall ist.

RecoverAnimation ist eine verschachtelte Klasse in ItemTouchHelper das die Touch-Animation der gewischten/gezogenen Elemente verwaltet. Obwohl der Name impliziert, dass es nur erholt sich die Position von Gegenständen, es ist eigentlich die einzige Klasse, die zum Wiederherstellen verwendet wird (Wischen/Ziehen abbrechen) und Elemente ersetzen (beim Wischen herausbewegen oder beim Ziehen ersetzen). Seltsame Namensgebung.

Es gibt eine boolesche Eigenschaft namens mIsPendingCleanup in RecoverAnimationdie ItemTouchHelper verwendet, um herauszufinden, ob das Entfernen des Elements ansteht. So ItemTouchHelpernach dem Anbringen a RecoverAnimation zum Element, setzt diese Eigenschaft nach einem erfolgreichen Auswischen, und die Animation wird nicht aus der Liste der Wiederherstellungsanimationen entfernt, solange diese Eigenschaft gesetzt ist. Das Problem ist, dass, mIsPendingCleanup wird immer für ein geklautes Element gesetzt, wodurch die RecoverAnimation damit das Element nie aus der Liste der Animationen entfernt wird. Selbst wenn Sie also die Position des Elements nach einem erfolgreichen Wischen wiederherstellen, wird es an die Position zurückgeschickt, an der Sie es entfernt haben, sobald Sie es berühren – da die RecoverAnimation bewirkt, dass die Animation an der zuletzt entfernten Position beginnt.

Lösung hierfür ist leider das kopieren ItemTouchHelper class-Quellcode in dasselbe Paket wie in der Support-Bibliothek und entfernen Sie die mIsPendingCleanup Eigentum aus der RecoverAnimation Klasse. Ich bin mir nicht sicher, ob dies von Google akzeptiert wird, und ich habe das Update noch nicht im Play Store gepostet, um zu sehen, ob es zu einer Ablehnung führt, aber möglicherweise finden Sie den Klassenquellcode aus der Support-Bibliothek v22.2.1 mit dem oben Gesagten erwähnt fix bei https://gist.github.com/kukabi/f46e1c0503d2806acbe2.

  • Würden Sie bitte einige Details zu dieser Lösung angeben. Kann es noch nicht bekommen

    – Klar

    12. Mai 2016 um 9:12 Uhr


  • Ihre Annahme gilt auch heute noch?

    – Richard Lee

    16. März 2017 um 16:44 Uhr


  • ” … geht davon aus, dass jeder geklaute Gegenstand irgendwann aus der Recycler-Ansicht entfernt wird..” vielleicht war es vor 100 Jahren ))

    – ekashking

    2. Juli 2021 um 6:46 Uhr


  • @ekashking nicht ganz. Vor ungefähr 6 Jahren, wenn Sie das Datum der Antwort überprüfen.

    – kukabi

    3. Juli 2021 um 7:10 Uhr

Benutzer-Avatar
Jan Bollacke

EIN schmutzige Problemumgehung Die Lösung für dieses Problem besteht darin, den ItemTouchHelper durch Aufrufen erneut anzuhängen ItemTouchHelper::attachToRecyclerView(RecyclerView) zweimal, die dann die private Methode aufruft ItemTouchHelper::destroyCallbacks(). destroyCallbacks() Entfernt die Elementdekoration und alle Listener, löscht aber auch alle RecoverAnimations.

Beachten Sie, dass wir anrufen müssen itemTouchHelper.attachToRecyclerView(null) zuerst zu tricksen ItemTouchHelper in den Gedanken, dass der zweite Anruf zu itemTouchHelper.attachToRecyclerView(recyclerView) ist eine neue Recycler-Ansicht.

Für weitere Details werfen Sie einen Blick in den Quellcode von ItemTouchHelper hier.

Beispiel für eine Problemumgehung:

RecyclerView recyclerView = findViewById(R.id.recycler_view);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);

...
// Workaround to reset swiped out views
itemTouchHelper.attachToRecyclerView(null);
itemTouchHelper.attachToRecyclerView(recyclerView);

Betrachten Sie es als schmutzige Problemumgehung, da diese Methode interne, nicht dokumentierte Implementierungsdetails von verwendet ItemTouchHelper.

Aktualisieren:

Von dem Dokumentation von ItemTouchHelper::attachToRecyclerView(RecyclerView):

Wenn TouchHelper bereits an eine RecyclerView angehängt ist, wird es zuerst von der vorherigen getrennt. Sie können diese Methode mit null aufrufen, um sie von der aktuellen RecyclerView zu trennen.

und in der Parameterdokumentation:

Die RecyclerView-Instanz, zu der Sie diesen Helfer hinzufügen möchten, oder null, wenn Sie ItemTouchHelper aus der aktuellen RecyclerView entfernen möchten.

So ist es zumindest teilweise dokumentiert.

Mit den neuesten anndroidX-Paketen habe ich dieses Problem immer noch, daher musste ich die @jimmy0251-Lösung ein wenig anpassen, um das Element korrekt zurückzusetzen (seine Lösung funktionierte nur beim ersten Wischen).

 override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                clipAdapter.notifyItemChanged(viewHolder.adapterPosition)
                itemTouchHelper.startSwipe(viewHolder)
            }

Beachten Sie, dass startSwipe() setzt die Wiederherstellungsanimationen des Gegenstands korrekt zurück.

  • Das Arbeiten Die Antwort wurde 5 Jahre nach der Veröffentlichung der Frage gegeben. Nicht zu fassen! 🙂

    – Eugen Kartojew

    6. März 2020 um 23:30 Uhr

  • Funktioniert nicht. Die Ansicht wird wiederhergestellt, aber wenn ich versuche, in ein anderes Element zu wischen, beginnt es in dem zurückgesetzten Element zu wischen.

    – Mateu

    24. April 2021 um 16:20 Uhr

Benutzer-Avatar
Carl B

Bei Verwendung LiveData eine Liste zu liefern a ListAdapteranrufen notifyItemChanged funktioniert nicht. Ich habe jedoch eine flüchtige Problemumgehung gefunden, bei der das erneute Anbringen der ItemTouchHelper zur Recycleransicht in onSwiped Rückruf als solches

val recyclerView = someRecyclerViewInYourCode

var itemTouchHelper: ItemTouchHelper? = null

val itemTouchCallback = object : ItemTouchHelper.Callback {
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction:Int) {
        itemTouchHelper?.attachToRecyclerView(null)
        itemTouchHelper?.attachToRecyclerView(recyclerView)
    }
}

itemTouchHelper = ItemTouchHelper(itemTouchCallback)

itemTouchHelper.attachToRecyclerView(recyclerView)

  • Das Arbeiten Die Antwort wurde 5 Jahre nach der Veröffentlichung der Frage gegeben. Nicht zu fassen! 🙂

    – Eugen Kartojew

    6. März 2020 um 23:30 Uhr

  • Funktioniert nicht. Die Ansicht wird wiederhergestellt, aber wenn ich versuche, in ein anderes Element zu wischen, beginnt es in dem zurückgesetzten Element zu wischen.

    – Mateu

    24. April 2021 um 16:20 Uhr

Benutzer-Avatar
Павел Карпычев

onSwiped niemals aufrufen, immer zurücksetzen

override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float {
    return 1f
}
override fun getSwipeEscapeVelocity(defaultValue: Float): Float {
    return Float.MAX_VALUE
}

  • Es gibt nur ein Problem dabei, dass onSwiped nie wirklich aufgerufen wird. Wir möchten ein Ereignis registrieren, wenn ein teilweiser Swipe stattgefunden hat.

    – Bawender Yandra

    11. Juli 2021 um 12:28 Uhr

1256510cookie-checkAndroid RecyclerView ItemTouchHelper Swipe rückgängig machen und Ansichtshalter wiederherstellen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy