2016-06-28 14 views
-1

Ich arbeite an einer App, die Bilder von einer Website anzeigt. Die Bilder haben alle unterschiedliche Höhen. Dies gilt auch für die Ansichten (Viewholders), in denen sie angezeigt werden.Probleme beim Ersetzen des Datensatzes von RecyclerView

Beim Anwenden eines Filters wird der vorherige Datensatz (also der derzeit sichtbare) entfernt, indem er direkt aus dem Datensatz gelöscht wird Adapter. Der Adapter wird benachrichtigt, dass dies passierte mit

final int removedSize = items.size(); 
items.clear(); 
notifyItemRangeRemoved(0, removedSize); 

Dies macht die alten Elemente animiert vom Bildschirm. Wenn diese Animation beendet ist, füge ich den neuen Datensatz mit

hinzu. Dies animiert die hinzugefügten Objekte. Das Seltsame ist, dass ich manchmal Lücken im RecyclerView bekomme, als ob der RecyclerView die neuen Dimensionen des ViewHolders beim Zeichnen aller Objekte nicht berücksichtigt. Dazu kommt, dass einige der Gegenstände buchstäblich übereinander liegen und wann immer sie wollen, in den Vordergrund treten. Die Gegenstände, die sich oben auf den Gegenständen befinden, die sich an der richtigen Position befinden, sind Gegenstände, die innerhalb der Lücken platziert werden sollten. Sie werden nicht in die Lücke zurückkehren, aber als ich den Gegenstandssatz manuell untersuchte, bemerkte ich, dass sie dort sein sollten.

Der RecyclerView ist das Kind einer SwipeRefreshLayout Ansicht, aber ich denke nicht, dass das ein Problem sein sollte.

Einige der Parameter I des RecyclerView festgelegt haben:

recents.setLayoutManager(layoutManager); 
recents.setHasFixedSize(false); 
recents.setItemViewCacheSize(100); 

Innerhalb der Layout-Datei

android:animationCache="false" 
android:scrollingCache="false" 

Was mache ich falsch?

Ich habe bereits eine kleine Verzögerung von 0,7 Sekunden hinzugefügt, um sicherzustellen, dass alle Animationen beendet sind, aber das scheint nicht viel zu helfen.

ItemAnimator:

@Override 
    public boolean animateAdd(RecyclerView.ViewHolder viewHolder) { 
     if (viewHolder.getItemViewType() != -8) { // ImageAdapter.ViewType.EMPTY = -8; 
      if (viewHolder.getLayoutPosition() > lastAddAnimatedItem) { 
       lastAddAnimatedItem++; 
       runEnterAnimation((ImageListView) viewHolder, viewHolder.getLayoutPosition()); 
       return false; 
      } 
     } 
     lastAddAnimatedItem = -6; 
     dispatchAddFinished(viewHolder); 
     return false; 
    } 

    @Override 
    public boolean animateRemove(RecyclerView.ViewHolder viewHolder) { 
     if (viewHolder.getItemViewType() != -8) { // ImageAdapter.ViewType.EMPTY = -8; 
      if (viewHolder.getLayoutPosition() > lastRemoveAnimatedItem) { 
       lastRemoveAnimatedItem++; 
       runExitAnimation((ImageListView) viewHolder, viewHolder.getLayoutPosition()); 
       return false; 
      } 
     } 

     lastRemoveAnimatedItem = -6; 
     dispatchRemoveFinished(viewHolder); 
     return false; 
    } 

    private void runEnterAnimation(final ImageListView holder, int position) { 
     final int screenHeight = Utils.getScreenHeight(holder.itemView.getContext()); 
     holder.itemView.setTranslationY(screenHeight + holder.itemView.getHeight()); 
     holder.itemView.animate() 
       .translationY(0) 
       .setStartDelay(150 + (20 * (position))) 
       .setInterpolator(new DecelerateInterpolator(3.f)) 
       .setDuration(700) 
       .setListener(new AnimatorListenerAdapter() { 
        @Override 
        public void onAnimationEnd(Animator animation) { 
         dispatchAddFinished(holder); 
        } 
       }) 
       .start(); 
    } 

    private void runExitAnimation(final ImageListView holder, int position) { 
     final int screenHeight = Utils.getScreenHeight(holder.itemView.getContext()); 
     holder.itemView.setTranslationY(0); 
     holder.itemView.animate() 
       .translationY(-screenHeight - holder.itemView.getHeight()) 
       .setStartDelay(Math.abs(20 * (position))) 
       .setInterpolator(new DecelerateInterpolator(3.f)) 
       .setDuration(700) 
       .setListener(new AnimatorListenerAdapter() { 
        @Override 
        public void onAnimationEnd(Animator animation) { 
         dispatchRemoveFinished(holder); 
        } 
       }) 
       .start(); 
    } 

EDIT:

Es scheint, dass das erste Element nach dem letzten sichtbaren Elemente, das auf dem Bildschirm an der falschen Stelle platziert.

Antwort

1

Ich bin seit mehr als einer Woche mit diesem Problem zu kämpfen, aber ich fand die Lösung:

ändern runEnterAnimation dazu:

private void runEnterAnimation(final ImageListView holder, int position) { 
     final int screenHeight = Utils.getScreenHeight(holder.itemView.getContext()); 
     holder.itemView.setTranslationY(screenHeight); 
     holder.itemView.animate() 
       .translationY(0) 
       .setStartDelay(150 + (20 * (position))) 
       .setInterpolator(new DecelerateInterpolator(3.f)) 
       .setDuration(700) 
       .setListener(new AnimatorListenerAdapter() { 
        @Override 
        public void onAnimationEnd(Animator animation) { 
         dispatchAddFinished(holder); 
         holder.itemView.setTranslationY(0f); 
        } 
        @Override 
        public void onAnimationCancel(Animator animation){ 
         holder.itemView.setTranslationY(0f); 
        } 
       }) 
       .start(); 
    } 

Beachten Sie die neuen Linien innerhalb des onAnimationEnd und die onAnimationCancel Rückrufe Dies stellt sicher, dass die Übersetzung des Elements immer auf die gewünschte Übersetzung eingestellt ist, für die die Animation animiert wurde.

runExitAnimation Ersetzen Sie diese mit:

private void runExitAnimation(final ImageListView holder, int position) { 
     final int screenHeight = Utils.getScreenHeight(holder.itemView.getContext()); 
     holder.itemView.setTranslationY(0); 
     holder.itemView.animate() 
       .translationY(-screenHeight) 
       .setStartDelay(Math.abs(20 * (position))) 
       .setInterpolator(new DecelerateInterpolator(3.f)) 
       .setDuration(700) 
       .setListener(new AnimatorListenerAdapter() { 
        @Override 
        public void onAnimationEnd(Animator animation) { 
         dispatchRemoveFinished(holder); 
         holder.itemView.setTranslationY(-screenHeight); 
        } 
        @Override 
        public void onAnimationCancel(Animator animation){ 
         holder.itemView.setTranslationY(-screenHeight); 
        } 
       }) 
       .start(); 
    } 

endAnimation Ersetzen Sie diese mit:

@Override 
    public void endAnimation(RecyclerView.ViewHolder item) { 
     super.endAnimation(item); 
     item.itemView.setTranslationY(0f); 
    } 

Dies wird sicherstellen, dass der Halter immer kehrt zu seiner ursprünglichen Position.

In Ihrem Adapter, fügen Sie die folgende Zeile in der onBindViewHolder Methode:

holder.itemView.setTranslationY(0f); 

Mit der Linie oben, erhalte ich einen seltsamer Fehler des ersten Elements eines anderen Datensatz im Hintergrund stecken, aber wenn Sie fügen Sie einen Hintergrund, der die gleiche Farbe wie der Hintergrund des RecyclerView zu Ihren Einzelteilen hat, dass der Fehler auch behoben wird.

Manchmal ist es sehr nützlich, Dinge aufzuschreiben, wie sie sind, um die Lösung zu sehen. Wie diesmal hat es mich auf die Lösung hingewiesen.

Verwandte Themen