web-dev-qa-db-de.com

Animieren Sie RecyclerView beim Scrollen

Gibt es eine Möglichkeit, die Elemente einer RecyclerView zu animieren, wenn ich sie scrolle?

Ich habe mir DefaultItemAnimator und RecyclerView.ItemAnimator angesehen, aber die Animationen scheinen nur aufgerufen zu werden, wenn sich der Datensatz geändert hat. Bitte korrigieren Sie mich, falls ich falsch liege.

Ich bin etwas verwirrt über RecyclerView.ItemAnimator.animateMove() wann heißt es? Ich habe einige Haltepunkte in diese Klasse eingefügt, aber keine davon stoppt meine App.

Zurück zu meiner Frage, wie kann ich die RecyclerView animieren? Ich möchte, dass einige Elemente eine andere Deckkraft haben, die auf einigen benutzerdefinierten Regeln beruht.


Ich habe noch ein bisschen mehr nachgedacht, es scheint, als wäre der Animationszug genau das, wonach ich suche. Diese Methoden werden von dispatchLayout() aufgerufen. Hier ist der Javadoc dieser Methode:

Wrapper um layoutChildren (), das die durch Layout verursachten Animationsänderungen behandelt . Animationen gehen davon aus, dass es fünf verschiedene Arten von Elementen gibt im Spiel:
PERSISTENT: Elemente sind vor und nach dem Layout sichtbar
ENTFERNT: Elemente waren vor dem Layout sichtbar und wurden von der App entfernt
ADDED: Elemente waren vor dem Layout nicht vorhanden und wurden von der App hinzugefügt
DISAPPEARING: Elemente sind vor/nach dem Datensatz vorhanden, wurden jedoch von .__ geändert. sichtbar für nicht sichtbar im Prozess des Layouts (sie wurden als Nebeneffekt von anderen Änderungen vom Bildschirm __. verschoben.)
APPEARING: Elemente sind vor/nach dem Datensatz vorhanden, wurden jedoch von .__ geändert. Nicht sichtbar bis sichtbar im Prozess des Layouts (sie wurden als Nebeneffekt anderer Änderungen auf den Bildschirm __. verschoben.)
Der Gesamtansatz ermittelt, welche Elemente vor/nach dem Layout und .__ vorhanden sind. Führt für jedes Element einen der fünf oben genannten Zustände aus. Dann die Animationen sind entsprechend eingerichtet:
PERSISTENT-Ansichten werden verschoben ({@link ItemAnimator # animateMove (ViewHolder, int, int, int, int)}) ENTFERNTE Ansichten werden entfernt ({@link ItemAnimator # animateRemove (ViewHolder)})
ADDED-Ansichten werden hinzugefügt ({@link ItemAnimator # animateAdd (ViewHolder)})
DISAPPEARING-Ansichten werden vom Bildschirm verschoben
ERSCHEINUNGSANSICHTEN werden auf dem Bildschirm verschoben

Bisher suche ich nach PERSISTENT, ENTFALLEN und ERSCHEINEN, aber diese Methoden werden wegen dieser Zeile hier nie aufgerufen:

boolean animateChangesSimple = mItemAnimator != null && mItemsAddedOrRemoved
            && !mItemsChanged;

mItemsAddedOrRemoved ist einfach immer false, so dass kein Callback jemals erreicht wird. Irgendeine Idee, wie man das Flag richtig setzt?

24
rekire

Am Ende habe ich eine OnScrollListener verwendet und sie in einer benutzerdefinierten animate()-Methode animiert. In meinem Fall dauert dieser Code nur 2 ms, sodass für die 60fps kein Problem besteht.

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(int newState) {
        if(newState == RecyclerView.SCROLL_STATE_IDLE) {
            // special handler to avoid displaying half elements
            scrollToNext();
        }
        animate();
    }

    @Override
    public void onScrolled(int dx, int dy) {
        animate();
    }
});
9
rekire

Ich habe es so gemacht. Könnte jemandem helfen Ich weiß nicht, ob es der beste Weg ist, aber es funktioniert gut für mich.

UPDATE: Um das schnelle Scrollen zu verhindern, überschreiben Sie die onViewDetachedFromWindow-Methode des Adapters und rufen Sie clearAnimation in der animierten Ansicht auf (in diesem Fall holder.itemView.clearAnimation()).

up_from_bottom.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:Android="http://schemas.Android.com/apk/res/Android"
 Android:shareInterpolator="@Android:anim/decelerate_interpolator">
<translate
    Android:fromXDelta="0%" Android:toXDelta="0%"
    Android:fromYDelta="100%" Android:toYDelta="0%"
    Android:duration="400" />
</set>

down_from_top.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:Android="http://schemas.Android.com/apk/res/Android"
 Android:shareInterpolator="@Android:anim/decelerate_interpolator">
<translate
    Android:fromXDelta="0%" Android:toXDelta="0%"
    Android:fromYDelta="-100%" Android:toYDelta="0%"
    Android:duration="400" />
</set>

Und zum Schluss diesen Code in onBindViewHolder von recyclerView setzen. Erstellen Sie ein Feld mit dem Namen lastPosition und initialisieren Sie es mit -1.

Animation animation = AnimationUtils.loadAnimation(context,
            (position > lastPosition) ? R.anim.up_from_bottom
                    : R.anim.down_from_top);
    holder.itemView.startAnimation(animation);
    lastPosition = position;
6
Vineet Ashtekar

Die beste Lösung ist, den Halter im Adapter in der Methode onBindViewHolder zu animieren. Ausschnitt aus dem Materialtest-Projekt Slidenerd:

@Override 
public void onBindViewHolder(ViewHolderBoxOffice holder, int position) {
    Movie currentMovie = mListMovies.get(position);
    //one or more fields of the Movie object may be null since they are fetched from the web 
    holder.movieTitle.setText(currentMovie.getTitle());


    //retrieved date may be null 
    Date movieReleaseDate = currentMovie.getReleaseDateTheater();
    if (movieReleaseDate != null) {
        String formattedDate = mFormatter.format(movieReleaseDate);
        holder.movieReleaseDate.setText(formattedDate);
    } else { 
        holder.movieReleaseDate.setText(Constants.NA);
    } 


    int audienceScore = currentMovie.getAudienceScore();
    if (audienceScore == -1) {
        holder.movieAudienceScore.setRating(0.0F);
        holder.movieAudienceScore.setAlpha(0.5F);
    } else { 
        holder.movieAudienceScore.setRating(audienceScore / 20.0F);
        holder.movieAudienceScore.setAlpha(1.0F);
    } 


    if (position > mPreviousPosition) {
        AnimationUtils.animateSunblind(holder, true);         
    } else { 
        AnimationUtils.animateSunblind(holder, false);

    } 
    mPreviousPosition = position;

hier ist ein link

0
CrazyFox