RecyclerView 中的 CardView:在填充时进行动画显示

22

我有一个使用CardView布局填充的回收视图(recycled view)。我注意到在许多应用中,这些项都有一个漂亮的动画效果进入,而不是像我的应用程序中那样突然出现。下面展示了我想要实现的示例:

图片描述

我应该如何使用swipeRefreshListener/adapter来触发此动画?我该如何通过我的适配器(adapter)实现它?

注意:我需要这个动画在RecyclerView第一次填充CardView项和它们包含的数据时也能被触发。

我的RecyclerView的适配器(adapter)如下所示:

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {

private String[] mDataset;
private String[] mClassDataset;
private int lastPosition = -1;
private Context context;

View view;


public static class ViewHolder extends RecyclerView.ViewHolder {

    public TextView mTextView;
    public TextView mClassDataView;
    CardView container;


    public ViewHolder(View itemView) {
        super(itemView);
        mTextView = (TextView)itemView.findViewById(R.id.grade);
        mClassDataView = (TextView)itemView.findViewById(R.id.class_name);
        container = (CardView)itemView.findViewById(R.id.card_view);
    }
}

public RecyclerAdapter(String[] myDataset, String[] classData, Context context) {
    mDataset = myDataset;
    mClassDataset = classData;
    this.context = context;

}

@Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View v = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.card_item, parent, false);

    ViewHolder vh = new ViewHolder(v);

    view = v;

    return vh;
}

@Override
public int getItemCount() {
    return mClassDataset.length;
}

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


    if (mDataset.length < mClassDataset.length) {

        holder.mTextView.setText("N/A");
        holder.mClassDataView.setText(mClassDataset[position]);

        if (mClassDataset[position].equals("N/A")) {

        }

    } else {
        holder.mTextView.setText(mDataset[position]);
        holder.mClassDataView.setText(mClassDataset[position]);
    }

    for (int i = 0; i < getItemCount(); i++) {

        animate(view, i);

    }
}

private void animate(final View view, final int position){

        Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
        view.startAnimation(animation);
        lastPosition = position;

    }

}
目前动画正在工作,但问题是所有项目都在同时被动画化。我尝试通过创建自定义的getChild()方法遍历项目,但那并没有起作用。不知何故,我需要单独访问/动画每个子元素,并可能在每个动画之间设置延迟。但是,我不确定如何实现这一点。我知道我可以使用 Handler 来设置延迟,但访问每个子元素是一个问题。
3个回答

44
使用这个自定义的 RecyclerView 类,它的行为类似于您发布截图的应用程序(Reddit Relay),在动画第一项时防止滚动。您可以根据需要自定义动画。
package net.leolink.android.testrecyclerviewentranceanimation;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * @author Leo on 2015/09/03
 */
public class MyRecyclerView extends RecyclerView {
    private boolean mScrollable;

    public MyRecyclerView(Context context) {
        this(context, null);
    }

    public MyRecyclerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mScrollable = false;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return !mScrollable || super.dispatchTouchEvent(ev);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        for (int i = 0; i < getChildCount(); i++) {
            animate(getChildAt(i), i);

            if (i == getChildCount() - 1) {
                getHandler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mScrollable = true;
                    }
                }, i * 100);
            }
        }
    }

    private void animate(View view, final int pos) {
        view.animate().cancel();
        view.setTranslationY(100);
        view.setAlpha(0);
        view.animate().alpha(1.0f).translationY(0).setDuration(300).setStartDelay(pos * 100);
    }
}


演示

演示


我应该更改我的布局,使用自定义RecyclerView而不是普通的RecyclerView吗?此外,在我的Activity中,我需要将其转换为自定义RecyclerView吗? - mlz7
是的,两个问题都可以翻译。 - Leo
这个很好用,谢谢。只是出于好奇,为什么需要包含你添加的所有构造函数呢?(我尝试创建一个自定义RecyclerView类,只有一个构造函数,而且没有处理可滚动变量,但事情没有按计划进行) - mlz7
不,你不必包含我写的所有构造函数,只有第二个构造函数会在XML中被调用(它之前没有起作用是因为我在第一个和第二个构造函数中使用了“this”而不是“super”)。此外,在这里必须禁用滚动,否则当用户在动画进行时向下滚动时,它会看起来很奇怪。顺便说一句,如果我的答案对你有用,请接受并授予我赏金 :) - Leo
1
@Leo
我有一个小问题:如果我将RecyclerView包装在SwipeRefreshLayout中,它会在我“拉动”SwipeRefreshLayout时立即触发动画。有没有办法防止这种情况发生?
- just_deko
显示剩余7条评论

4

首先定义动画:

<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%p" android:toXDelta="0"
    android:duration="300"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
    android:duration="300" />
</set>

然后在您的适配器中设置它:

    @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.container, 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.push_left_in);
        viewToAnimate.startAnimation(animation);
        lastPosition = position;
    }
}

参考来源:RecyclerView:如何创建插入动画效果?


这几乎是我所需要的,但是我需要单独对它们进行动画处理,而不是同时处理所有项目。 - mlz7
@Steve 对不起,我没有太多经验或时间,因为我是一名高中学生。 - LonelyIdiot
如何在RecyclerView中添加或删除项目动画。 - akhil batlawala
@steve,lastPosition是从哪里来的?是列表的大小(listSize-1)吗? - Subhan Ali

3

对于RecyclerView,您可以使用ItemAnimators通过使用此方法设置它们:

RecyclerView.setItemAnimator(RecyclerView.ItemAnimator animator)

有一些库可以实现这个 ItemAnimator,例如这个库:https://github.com/wasabeef/recyclerview-animators


是的,我看了那个库,但它没有我想要的东西。 - mlz7
@Steve 这就是你要做的。如果你找不到完全符合你要求的,那么你就得自己写。 - tachyonflux
@karaokyo,这不是在填充RecyclerView时处理动画的方法。 - mlz7
@Steve 那它们用来做什么的? - tachyonflux
要使用itemAnimators完成我正在尝试的操作,您需要逐个添加RecyclerView项,设置动画,然后刷新视图(对于所有填充视图重复);所有这些都是不必要的繁琐工作,因为应该可以在适配器本身内完成。 - mlz7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接