2015-07-14 5 views
15

Ich habe ein Entfernen auf Swipe, bekommt, das einen Hintergrund zieht (ähnlich wie die Inbox App), die von einer ItemTouchHelper implementiert - von der onChilDraw Methode überschreibt und ein Rechteck auf der bereitgestellten Leinwand Zeichnung:RecyclerView ItemTouchHelper Swipe entfernen Animation

ItemTouchHelper mIth = new ItemTouchHelper(
     new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) { 

      public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 
       remove(viewHolder.getAdapterPosition()); 
      } 

      public boolean onMove(RecyclerView recyclerview, RecyclerView.ViewHolder v, RecyclerView.ViewHolder target) { 
       return false; 
      } 

      @Override 
      public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { 

       View itemView = viewHolder.itemView; 

       Drawable d = ContextCompat.getDrawable(context, R.drawable.bg_swipe_item_right); 
       d.setBounds(itemView.getLeft(), itemView.getTop(), (int) dX, itemView.getBottom()); 
       d.draw(c); 

       super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 
      } 
     }); 

die Methode remove oben im Adapter genannt ist:

public void remove(int position) { 
     items.remove(position); 
     notifyItemRemoved(position); 
    } 

der Hintergrund schön zieht, aber wenn notifyItemRemoved (nach Mr. Debugger) aufgerufen wird, löscht das RecyclerView zuerst meinen schönen grünen Hintergrund, und schiebt dann die beiden ein angrenzende Gegenstände zusammen.

enter image description hereenter image description here

ich mag es dort um den Hintergrund zu halten, während sie das tut (wie die Inbox App). Gibt es eine Möglichkeit, das zu tun?

Antwort

2

Ich hatte das gleiche Problem und ich wollte nicht eine neue lib vorstellen, nur um es zu beheben. Die RecyclerView löscht nicht Ihren schönen grünen Hintergrund, es zeichnet sich nur neu und Ihre ItemTouchHelper Zeichnung wird nicht mehr gezeichnet. Eigentlich ist es Zeichnung, aber die dX ist 0 und zeichnet von der itemView.getLeft() (die 0 ist) bis dX (was 0 ist), so dass Sie nichts sehen. Und es zeichnet zu viel, aber ich werde später darauf zurückkommen.

Wie auch immer zurück in den Hintergrund während Zeilen animieren: Ich konnte es nicht innerhalb ItemTouchHelper und onChildDraw. Am Ende musste ich noch einen anderen Dekorateur dazu hinzufügen.Es geht in diese Richtung:

public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 
    if (parent.getItemAnimator().isRunning()) { 
     // find first child with translationY > 0 
     // draw from it's top to translationY whatever you want 

     int top = 0; 
     int bottom = 0; 

     int childCount = parent.getLayoutManager().getChildCount(); 
     for (int i = 0; i < childCount; i++) { 
      View child = parent.getLayoutManager().getChildAt(i); 
      if (child.getTranslationY() != 0) { 
       top = child.getTop(); 
       bottom = top + (int) child.getTranslationY();      
       break; 
      } 
     } 

     // draw whatever you want 

     super.onDraw(c, parent, state); 
    } 
} 

Dieser Code nimmt in nur Konto Reihen Animieren, aber Sie sollten auch prüfen, Zeilen herunterkommen. Das passiert, wenn du die letzte Zeile löschst, die darüber liegenden Zeilen werden auf diesen Bereich animiert.

Als ich sagte, dass Ihr ItemTouchHelper zu viel zeichnet, was ich meinte war: Sieht aus wie ItemTouchHelper hält ViewHolder s von entfernten Zeilen für den Fall, dass sie wiederhergestellt werden müssen. Es ruft auch onChildDraw für diese VHs zusätzlich zu dem VH, der geklaut wird. Ich bin mir nicht sicher über die Auswirkungen dieses Verhaltens auf die Speicherverwaltung, aber ich brauchte eine zusätzliche Überprüfung am Anfang von onChildDraw, um zu vermeiden, dass ich für "Fantom" -Zeilen zeichne.

In Ihrem Fall ist es Zeichnung von links = 0 nach rechts = 0, so dass Sie nichts sehen, aber der Overhead ist da. Wenn Sie beginnen, die zuvor entfernten Zeilen zu sehen, die ihren Hintergrund zeichnen, ist das der Grund.

EDIT: Ich hatte einen Versuch, dieses blog post und dieses github repo.

1

Ich schaffte es mit der Wasabeefs's recyclerview-animators Bibliothek zu arbeiten.

Mein ViewHolder erstreckt sich nun die zur Verfügung gestellt AnimateViewHolder Bibliothek:

class MyViewHolder extends AnimateViewHolder { 

    TextView textView; 

    public MyViewHolder(View itemView) { 
     super(itemView); 
     this.textView = (TextView) itemView.findViewById(R.id.item_name); 
    } 

    @Override 
    public void animateAddImpl(ViewPropertyAnimatorListener listener) { 
     ViewCompat.animate(itemView) 
       .translationY(0) 
       .alpha(1) 
       .setDuration(300) 
       .setListener(listener) 
       .start(); 
    } 

    @Override 
    public void preAnimateAddImpl() { 
     ViewCompat.setTranslationY(itemView, -itemView.getHeight() * 0.3f); 
     ViewCompat.setAlpha(itemView, 0); 
    } 

    @Override 
    public void animateRemoveImpl(ViewPropertyAnimatorListener listener) { 
     ViewCompat.animate(itemView) 
       .translationY(0) 
       .alpha(1) 
       .setDuration(300) 
       .setListener(listener) 
       .start(); 
    } 

} 

Die Funktion overrided Implementierungen sind identisch zu dem, was in recyclerview-Animateure readme auf GitHub.

Es scheint auch notwendig, den ItemAnimator auf einen benutzerdefinierten ein und stellen Sie die removeDuration auf 0 (oder ein anderen niedrigen Wert - das ist etwas Flackern zu verhindern) zu ändern:

recyclerView.setItemAnimator(new SlideInLeftAnimator()); 
    recyclerView.getItemAnimator().setRemoveDuration(0); 

Dies verursacht keine Probleme Als normale (nicht wischende) Entfernungsanimation wird diejenige im AnimateViewHolder verwendet.

Alle anderen Code wurde gleich wie in der Frage gehalten. Ich habe noch nicht die Zeit gehabt, um die inneren Abläufe herauszufinden, aber wenn jemand Lust hat, es zu tun, ist es frei, diese Antwort zu aktualisieren.

Update: Einstellung recyclerView.getItemAnimator().setRemoveDuration(0); bricht tatsächlich die "Rebind" -Animation der Swipe. Glücklicherweise löst das Entfernen dieser Zeile und das Festlegen einer längeren Dauer in animateRemoveImpl (500 funktioniert für mich) auch das Flimmerproblem.

Update 2: Stellt fest, dass ItemTouchHelper.SimpleCallback ItemAnimator die Animationsdauern verwendet, weshalb die obige setRemoveDuration (0) die Swipe-Animation bricht. Überschreiben Sie einfach die Methode getAnimationDuration zu:

löst dieses Problem.