Подтвердить что ты не робот

Анимация RecyclerView при прокрутке

Есть ли способ анимировать элементы RecyclerView при прокрутке его?

Я взглянул на DefaultItemAnimator и RecyclerView.ItemAnimator, но эти анимации, кажется, вызывается только в том случае, если набор данных изменился, пожалуйста, исправьте меня, если я ошибаюсь.

Я немного запутался в RecyclerView.ItemAnimator.animateMove(), когда он называется? Я помещал некоторые точки останова в этот класс, но ни один из них не останавливает мое приложение.

Однако вернемся к моему вопросу, как я могу оживить RecyclerView? Я хочу, чтобы некоторые элементы имели другую непрозрачность, зависело от некоторых пользовательских правил.


Я сделал еще несколько reaseach, кажется, что движение анимации - это именно то, что я ищу. Эти методы вызывают из dispatchLayout(). Вот javadoc этого метода:

Обертка вокруг layoutChildren(), которая обрабатывает анимацию изменений, вызванных макетом.  Анимация работает при условии, что существует пять различных видов предметов  в игре:
 PERSISTENT: элементы видны до и после макета
 УДАЛЕН: элементы были видны перед макетом и были удалены приложением
 ADDED: элементы не существовали до макета и были добавлены приложением
 ИСКАЖЕНИЕ: элементы существуют в наборе данных до/после, но изменены с  видимые для невидимых в процессе компоновки (они были удалены  экран как побочный эффект других изменений)
 APPEARING: элементы существуют в наборе данных до/после, но изменены с  невидимые для видимости в процессе компоновки (они были перемещены на  экран как побочный эффект других изменений)
 Общий подход определяет, какие элементы существуют до/после макета и  для каждого из предметов входит одно из пяти состояний. Затем анимация  соответственно настроены:
 Представления PERSISTENT перемещаются ({@link ItemAnimator # animateMove (ViewHolder, int, int, int, int)})  УДАЛЕННЫЕ виды удаляются ({@link ItemAnimator # animateRemove (ViewHolder)})
 Добавлены виды ADDED ({@link ItemAnimator # animateAdd (ViewHolder)})
 Представления DISAPPEARING перемещаются за пределы экрана
 Представления вида APPEARING перемещаются на экран

До сих пор я ищу ПОСТОЯННОЕ, ИСКЛЮЧИТЕЛЬНОЕ И ПОЯВЛЕНИЕ, но эти методы никогда не вызываются из-за этой строки здесь:

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

mItemsAddedOrRemoved просто всегда false, поэтому ни один из этих обратных вызовов не достигается. Любая идея, как правильно установить флаг?

4b9b3361

Ответ 1

Я закончил использование OnScrollListener и анимировал его в пользовательском методе animate(). В моем случае этот код занимает всего 2 мс, так что это не проблема для 60 кадров в секунду.

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

Ответ 2

Я сделал это так. Может помочь кому-то. Я не знаю, лучший ли это для этого, но отлично работает для меня.

UPDATE: Чтобы исправить быстрое поведение прокрутки, переопределите метод onViewDetachedFromWindow адаптера и вызовите clearAnimation на анимированном представлении (в данном случае 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>

И, наконец, поместите этот код в onBindViewHolder из recyclerView. Создайте поле под названием lastPosition и инициализируйте его до -1.

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

Ответ 3

Хорошим решением является анимировать держатель в адаптере в методе onBindViewHolder. Фрагмент, взятый из проекта Material Test 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;

здесь ссылка