【问题标题】:CardView within RecyclerView: animation while populatingRecyclerView 中的 CardView:填充时的动画
【发布时间】:2015-08-27 02:47:40
【问题描述】:

我有一个循环视图,其中填充了 CardView 布局。我注意到在许多应用程序中,这些项目有一个很好的动画入口,而不是像它们目前在我的应用程序中那样突然出现。我正在尝试实现的一个示例如下所示:

如何使用我的 swipeRefreshListener/adapter 来触发这个动画?我将如何通过我的适配器实现这一点?

注意:当 RecyclerView 首次填充 CardView 项目及其包含的数据时,我还需要触发此动画。

我的 RecyclerView 的适配器如下图:

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 来设置延迟,但是访问每个孩子是一个问题。

【问题讨论】:

    标签: android android-layout


    【解决方案1】:

    使用 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吗?另外,我会在我的活动中投射到我的自定义回收站视图吗?
    • 对这两个问题都是:)
    • 这非常感谢。只是出于好奇,为什么需要包含您添加的所有构造函数? (我尝试使用单个构造函数创建一个自定义 RecyclerView 类,并且不处理可滚动变量,但没有成功)
    • 不,你不必包括我写的所有构造函数,如果你在 XML 中使用它只会调用第二个(它对你不起作用,因为我使用了 'this'而不是第一个和第二个构造函数中的“超级”)。而且您必须在此处禁用滚动,否则当您在动画进行时用户向下滚动时,它看起来会很奇怪。顺便说一句,如果我的回答对你有用,请接受并奖励我:)
    • @Leo 我有一个小问题:如果我将 recyclerview 包装在一个 swiprefreshlayout 中,它会在我“拉”swiperefreh 时立即触发动画。有没有办法防止这种情况发生?
    【解决方案2】:

    首先定义动画:

    <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 : How to create insert animation effect?

    【讨论】:

    • 这几乎是我所需要的,除了让所有项目同时动画,我需要单独为它们制作动画
    • @Steve 对不起,我是一名高中生,没有太多经验或时间
    • 如何在recyclerview中添加remove item动画
    • @steve lastPosition 来自哪里?是列表的大小(listSize-1)吗?
    【解决方案3】:

    对于 RecyclerView,您可以通过以下方法设置 ItemAnimators:

    RecyclerView.setItemAnimator(RecyclerView.ItemAnimator animator)
    

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

    【讨论】:

    • 是的,我查看了那个库,但它没有我要找的东西
    • @Steve 你就是这样做的。如果你找不到你要找的东西,你就必须自己写。
    • @karaokyo 这不是您在填充回收站视图时处理动画的方式
    • @Steve 那他们是干什么用的?
    • @karaokyo 要完成我尝试使用 itemAnimators 所做的事情,您需要一个一个地添加 RecyclerView 项目,设置动画器,然后刷新视图(对所有填充视图重复);当应该可以在适配器本身内完成时,所有这些都是不必要的乏味
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-02
    • 1970-01-01
    • 2015-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多