Как оживить элементы RecyclerView, когда они появляются

Как я могу анимировать элементы RecyclerView, когда они появляются?

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

Есть идеи как этого добиться?

Ответ 1

Сделано просто только с XML

Посетите Gist Link

Рез/аним /layout_animation.xml

  <?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/item_animation_fall_down"
    android:animationOrder="normal"
    android:delay="15%" />

Рез/аним /item_animation_fall_down.xml

<translate
    android:fromYDelta="-20%"
    android:toYDelta="0"
    android:interpolator="@android:anim/decelerate_interpolator"
    />

<alpha
    android:fromAlpha="0"
    android:toAlpha="1"
    android:interpolator="@android:anim/decelerate_interpolator"
    />

<scale
    android:fromXScale="105%"
    android:fromYScale="105%"
    android:toXScale="100%"
    android:toYScale="100%"
    android:pivotX="50%"
    android:pivotY="50%"
    android:interpolator="@android:anim/decelerate_interpolator"
    />

Используйте в макетах и recylcerview, как:

<android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layoutAnimation="@anim/layout_animation"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

Ответ 2

EDIT:

В соответствии с документацией ItemAnimator:

Этот класс определяет анимации, которые происходят на элементах, поскольку изменения внесены в адаптер.

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

Вот как вы можете анимировать элементы RecyclerView, когда они появляются с помощью CustomAdapter:

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder>
{
    private Context context;

    // The items to display in your RecyclerView
    private ArrayList<String> items;
    // Allows to remember the last item shown on screen
    private int lastPosition = -1;

    public static class ViewHolder extends RecyclerView.ViewHolder
    {
        TextView text;
        // You need to retrieve the container (ie the root ViewGroup from your custom_item_layout)
        // It the view that will be animated
        FrameLayout container;

        public ViewHolder(View itemView)
        {
            super(itemView);
            container = (FrameLayout) itemView.findViewById(R.id.item_layout_container);
            text = (TextView) itemView.findViewById(R.id.item_layout_text);
        }
    }

    public CustomAdapter(ArrayList<String> items, Context context)
    {
        this.items = items;
        this.context = context;
    }

    @Override
    public CustomAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_item_layout, parent, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position)
    {
        holder.text.setText(items.get(position));

        // Here you apply the animation when the view is bound
        setAnimation(holder.itemView, position);
    }

    /**
     * Here is the key method to apply the animation
     */
    private void setAnimation(View viewToAnimate, int position)
    {
        // If the bound view wasn't previously displayed on screen, it animated
        if (position > lastPosition)
        {
            Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        }
    }
}

И ваш custom_item_layout будет выглядеть так:

<FrameLayout
    android:id="@+id/item_layout_container"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/item_layout_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceListItemSmall"
        android:gravity="center_vertical"
        android:minHeight="?android:attr/listPreferredItemHeightSmall"/>

</FrameLayout>

Дополнительные сведения о CustomAdapters и RecyclerView см. в этом обучении по официальной документации.

Проблемы с быстрой прокруткой

Использование этого метода может вызвать проблемы с быстрой прокруткой. Представление может быть повторно использовано во время анимации. Чтобы избежать этого, рекомендуется очистить анимацию при отсоединении.

    @Override
    public void onViewDetachedFromWindow(final RecyclerView.ViewHolder holder)
    {
        ((CustomViewHolder)holder).clearAnimation();
    }

В CustomViewHolder:

    public void clearAnimation()
    {
        mRootLayout.clearAnimation();
    }

Старый ответ:

Посмотрите Gabriele Mariotti repo, я уверен, что вы найдете то, что вам нужно. Он предоставляет простые ItemAnimators для RecyclerView, такие как SlideInItemAnimator или SlideScaleItemAnimator.

Ответ 3

Я анимировал появление элементов Recyclerview, когда они впервые появляются, как показано в коде ниже. Возможно, это кому-нибудь пригодится.

private final static int FADE_DURATION = 1000; //FADE_DURATION in milliseconds

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

    holder.getTextView().setText("some text");

    // Set the view to fade in
    setFadeAnimation(holder.itemView);            
}

private void setFadeAnimation(View view) {
    AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
    anim.setDuration(FADE_DURATION);
    view.startAnimation(anim);
}

Вы также можете заменить setFadeAnimation() на следующую setScaleAnimation() чтобы анимировать внешний вид элементов, масштабируя их из точки:

private void setScaleAnimation(View view) {
    ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    anim.setDuration(FADE_DURATION);
    view.startAnimation(anim);
}

Приведенный выше код имеет некоторые недостатки, поскольку при прокрутке элементы RecyclerView всегда исчезают или масштабируются. Если вы хотите, вы можете добавить код, чтобы позволить анимации происходить при первом создании фрагмента или действия, содержащего RecyclerView (например, получить системное время при создании и разрешить анимацию только в течение первых миллисекунд FADE_DURATION).

Ответ 4

Я создал анимацию из pbm answer с небольшим modification, чтобы анонимность выполнялась только один раз

в другом слове Animation appear with you scroll down only

private int lastPosition = -1;

private void setAnimation(View viewToAnimate, int position) {
    // If the bound view wasn't previously displayed on screen, it animated
    if (position > lastPosition) {
        ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        anim.setDuration(new Random().nextInt(501));//to make duration random number between [0,501)
        viewToAnimate.startAnimation(anim);
        lastPosition = position;
    }
}

и в onBindViewHolder вызовите функцию

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

holder.getTextView().setText("some text");

// call Animation function
setAnimation(holder.itemView, position);            
}

Ответ 6

Хорошее место для начала: https://github.com/wasabeef/recyclerview-animators/blob/master/animators/src/main/java/jp/wasabeef/recyclerview/adapters/AnimationAdapter.java

Вам даже не нужна полная библиотека, этого класса достаточно. Затем, если вы просто реализуете свой класс адаптера, предоставляя аниматор следующим образом:

@Override
protected Animator[] getAnimators(View view) {
    return new Animator[]{
            ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0)
    };
}

@Override
public long getItemId(final int position) {
    return getWrappedAdapter().getItemId(position);
}

вы увидите элементы, появляющиеся снизу, когда они прокручиваются, а также избегают проблемы с быстрым прокруткой.

Ответ 7

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

Исходный код, который я использовал для анимации каждого элемента в recyclerview, можно найти здесь:

http://frogermcs.github.io/Instagram-with-Material-Design-concept-is-getting-real/

Но я буду копировать и вставлять код в случае разрыва ссылки.

ШАГ 1: Установите это внутри метода onCreate, чтобы обеспечить, чтобы анимация запускалась только один раз:

if (savedInstanceState == null) {
    pendingIntroAnimation = true;
}

ШАГ 2: Вам нужно будет поместить этот код в метод, в котором вы хотите запустить анимацию:

if (pendingIntroAnimation) {
    pendingIntroAnimation = false;
    startIntroAnimation();
}

В ссылке писатель анимирует значки на панели инструментов, поэтому он поместил ее внутри этого метода:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);
    inboxMenuItem = menu.findItem(R.id.action_inbox);
    inboxMenuItem.setActionView(R.layout.menu_item_view);
    if (pendingIntroAnimation) {
        pendingIntroAnimation = false;
        startIntroAnimation();
    }
    return true;
}

ШАГ 3: Теперь напишите логику для startIntroAnimation():

private static final int ANIM_DURATION_TOOLBAR = 300;

private void startIntroAnimation() {
    btnCreate.setTranslationY(2 * getResources().getDimensionPixelOffset(R.dimen.btn_fab_size));

    int actionbarSize = Utils.dpToPx(56);
    toolbar.setTranslationY(-actionbarSize);
    ivLogo.setTranslationY(-actionbarSize);
    inboxMenuItem.getActionView().setTranslationY(-actionbarSize);

    toolbar.animate()
            .translationY(0)
            .setDuration(ANIM_DURATION_TOOLBAR)
            .setStartDelay(300);
    ivLogo.animate()
            .translationY(0)
            .setDuration(ANIM_DURATION_TOOLBAR)
            .setStartDelay(400);
    inboxMenuItem.getActionView().animate()
            .translationY(0)
            .setDuration(ANIM_DURATION_TOOLBAR)
            .setStartDelay(500)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    startContentAnimation();
                }
            })
            .start();
}

Моя предпочтительная альтернатива:

Я предпочел бы анимировать весь recyclerview вместо элементов внутри recyclerview.

ШАГ 1 и 2 остаются теми же.

В STEP 3, как только ваш вызов API вернется с вашими данными, я начну анимацию.

private void startIntroAnimation() {
    recyclerview.setTranslationY(latestPostRecyclerview.getHeight());
    recyclerview.setAlpha(0f);
    recyclerview.animate()
            .translationY(0)
            .setDuration(400)
            .alpha(1f)
            .setInterpolator(new AccelerateDecelerateInterpolator())
            .start();
}

Это позволит анимировать весь ваш recyclerview, чтобы он летел в нижней части экрана.

Ответ 8

Создайте этот метод в своем адаптере recyclerview

private void setZoomInAnimation(View view) {
        Animation zoomIn = AnimationUtils.loadAnimation(context, R.anim.zoomin);// animation file 
        view.startAnimation(zoomIn);
    }

И, наконец, добавьте эту строку кода в onBindViewHolder

setZoomInAnimation(holder.itemView);

Ответ 9

Просто расширяет ваш адаптер, как показано ниже

public class RankingAdapter extends AnimatedRecyclerView<RankingAdapter.ViewHolder> 

И добавьте супер метод к onBindViewHolder

@Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        super.onBindViewHolder(holder, position);

Это автоматизирует способ создания анимированного адаптера, такого как "Basheer AL-MOMANI"

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;

import java.util.Random;

/**
 * Created by eliaszkubala on 24.02.2017.
 */
public class AnimatedRecyclerView<T extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<T> {


    @Override
    public T onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public void onBindViewHolder(T holder, int position) {
        setAnimation(holder.itemView, position);
    }

    @Override
    public int getItemCount() {
        return 0;
    }

    protected int mLastPosition = -1;

    protected void setAnimation(View viewToAnimate, int position) {
        if (position > mLastPosition) {
            ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            anim.setDuration(new Random().nextInt(501));//to make duration random number between [0,501)
            viewToAnimate.startAnimation(anim);
            mLastPosition = position;
        }
    }

}

Ответ 10

Добавьте эту строку в RecyclerView.xml

android:animateLayoutChanges="true"