2015-07-14 13 views
15

ho un rimuovere il colpo, che disegna uno sfondo (molto simile l'applicazione Posta in arrivo), implementato da un ItemTouchHelper - sovrascrivendo il metodo onChilDraw e disegnare un rettangolo sulla tela forniti:RecyclerView ItemTouchHelper colpo rimuovere animazione

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

il metodo remove chiamato sopra è nel adattatore:

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

lo sfondo tira fuori bene, ma quando viene chiamato notifyItemRemoved (secondo il signor Debugger), il RecyclerView elimina prima la mia bella sfondo verde, e poi spinge i due a oggetti vicini insieme.

enter image description hereenter image description here

vorrei così almeno il fondo lì mentre lo fa (proprio come l'applicazione Posta in arrivo). C'è un modo per farlo?

risposta

2

Ho avuto lo stesso problema e non volevo introdurre una nuova libreria per risolvere il problema. Lo RecyclerView non sta eliminando il tuo bellissimo sfondo verde, si sta semplicemente ridisegnando da solo e il tuo ItemTouchHelper non sta più disegnando. In realtà sta disegnando ma lo dX è 0 e sta traendo da itemView.getLeft() (che è 0) a dX (che è 0) quindi non vedi nulla. E sta disegnando troppo, ma ci tornerò più tardi.

In ogni caso tornare allo sfondo mentre le file animano: non potevo farlo entro ItemTouchHelper e onChildDraw. Alla fine ho dovuto aggiungere un altro elemento decoratore per farlo.Segue queste righe:

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

Questo codice prende in considerazione solo le file che animano, ma dovresti considerare anche le righe che scendono. Ciò accade se si cancella l'ultima riga, le righe sopra animeranno verso quello spazio.

Quando ho detto che ItemTouchHelper sta tracciando troppo, ciò che intendevo era: Sembra che ItemTouchHelper conservi ViewHolder s di righe rimosse nel caso in cui debbano essere ripristinate. Chiama anche onChildDraw per quei VH in aggiunta alla VH che viene strisciata. Non sono sicuro delle implicazioni sulla gestione della memoria di questo comportamento, ma avevo bisogno di un ulteriore controllo all'inizio di onChildDraw per evitare di disegnare per le righe "fantom".

if (viewHolder.getAdapterPosition() == -1) { 
    return; 
} 

Nel tuo caso si tratta di disegno da sinistra = 0 a destra = 0 quindi non si vede nulla, ma la testa è lì. Se inizi a vedere righe precedentemente cancellate disegnando i loro sfondi, questo è il motivo.

EDIT: Ho provato questo, vedere questo blog post e questo github repo.

1

Sono riuscito a farlo funzionare utilizzando la libreria Wasabeefs's recyclerview-animators.

mio ViewHolder estende ora AnimateViewHolder condizione della biblioteca:

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

} 

Le implementazioni di funzione overrided sono identici a ciò che è nel readme recyclerview-animatori su github.

Sembra anche necessario cambiare l'ItemAnimator ad uno personalizzato e impostare il removeDuration a 0 (o di un altro valore basso - questo è quello di evitare che qualche sfarfallio):

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

Ciò non causa alcun problema poiché l'animazione di rimozione normale (non a scorrimento) utilizzata è quella di AnimateViewHolder.

Tutti gli altri codici sono stati mantenuti come nella domanda. Non ho ancora avuto il tempo di capire il funzionamento interno di questo, ma se qualcuno ha voglia di farlo, si senta libero di aggiornare questa risposta.

Aggiornamento: l'impostazione recyclerView.getItemAnimator().setRemoveDuration(0); interrompe effettivamente l'animazione "rebind" dello scorrimento. Fortunatamente, rimuovere quella linea e impostare una durata più lunga in animateRemoveImpl (500 funziona per me) risolve anche il problema di sfarfallio.

Aggiornamento 2: Si scopre che ItemTouchHelper.SimpleCallback utilizza le durate dell'animazione di ItemAnimator, motivo per cui il setRemoveDuration (0) precedente interrompe l'animazione di scorrimento. Semplicemente sovrascrivendo il metodo getAnimationDuration a:

@Override 
public long getAnimationDuration(RecyclerView recyclerView, int animationType, float animateDx, float animateDy) { 
    return animationType == ItemTouchHelper.ANIMATION_TYPE_DRAG ? DEFAULT_DRAG_ANIMATION_DURATION 
      : DEFAULT_SWIPE_ANIMATION_DURATION; 
} 

risolve questo problema.

Problemi correlati