Как анимировать элементы RecyclerView при их появлении

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

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

есть идеи, как этого достичь?

9 ответов


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

ответ :

взгляните на РЕПО Габриэле Мариотти, я уверен, что вы найдете то, что вам нужно. Он предоставляет простые ItemAnimators для RecyclerView, такие как SlideInItemAnimator или SlideScaleItemAnimator.


Я анимированные исчезает в 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).


Я создал анимацию из ответ pbm мало 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's 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);            
}

вы можете добавить атрибут android:layoutAnimation="@anim/rv_item_animation " в RecyclerView следующим образом:

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"                                        
    android:layoutAnimation="@anim/layout_animation_fall_down"
    />

спасибо за отличную статью здесь: https://proandroiddev.com/enter-animation-using-recyclerview-and-layoutanimation-part-1-list-75a874a5d213


хорошее место для начала это: 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);
}

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


анимация элементов в 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();
}

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

@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 остается тем же самым.

на Шаге 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 так, что он будет летать в нижней части экрана.


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

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

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

setZoomInAnimation(holder.itemView);


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

public class RankingAdapter extends AnimatedRecyclerView<RankingAdapter.ViewHolder> 

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

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

это автоматизировать способ создания анимированного адаптера, как "Basheer Аль-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;
        }
    }

}

добавьте эту строку в RecyclerView.в XML

android:animateLayoutChanges="true"