Android 如何在RecyclerView项出现时设置其动画

Android 如何在RecyclerView项出现时设置其动画,android,android-layout,android-recyclerview,Android,Android Layout,Android Recyclerview,当出现时,如何设置RecyclerView项目的动画 默认项“动画制作”仅在设置回收器数据后添加或删除数据时才进行动画制作。我是新开发的应用程序,不知道从哪里开始 有什么办法可以做到这一点吗?编辑: 根据: 此类定义对适配器进行更改时在项目上发生的动画 因此,除非您将项目逐个添加到RecyclerView中,并在每次迭代时刷新视图,否则我认为ItemAnimator不是您需要的解决方案 以下是如何使用CustomAdapter设置RecyclerView项出现时的动画: public class

当出现时,如何设置RecyclerView项目的动画

默认项“动画制作”仅在设置回收器数据后添加或删除数据时才进行动画制作。我是新开发的应用程序,不知道从哪里开始


有什么办法可以做到这一点吗?

编辑:

根据:

此类定义对适配器进行更改时在项目上发生的动画

因此,除非您将项目逐个添加到
RecyclerView
中,并在每次迭代时刷新视图,否则我认为
ItemAnimator
不是您需要的解决方案

以下是如何使用CustomAdapter设置
RecyclerView
项出现时的动画:

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;
        }
    }
}
在CustomViewHolder上:

    public void clearAnimation()
    {
        mRootLayout.clearAnimation();
    }
旧答案:


看看吧,我相信你会找到你需要的。他为RecyclerView提供了简单的项目动画师,如SlideInItemAnimator或SlideScaleItemAnimator。

一个好的起点是:

您甚至不需要完整的库,这个类就足够了。 然后,如果您只是实现了适配器类,并提供如下动画:

@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);
}
<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"                                        
    android:layoutAnimation="@anim/layout_animation_fall_down"
    />

您将看到项目在滚动时从底部显示,这也避免了快速滚动的问题。

当项目绑定到适配器中时,在recyclerview中设置项目动画可能不是最好的主意,因为这可能会导致recyclerview中的项目以不同的速度设置动画。在我的例子中,recyclerview末尾的项目比顶部的项目更快地移动到它们的位置,因为顶部的项目需要进一步移动,所以它看起来不整洁

我用来将每个项目动画化到recyclerview的原始代码可以在这里找到:

但我会复制并粘贴代码,以防链接中断

步骤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()编写逻辑:

我的首选方案:

我宁愿为整个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 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
的片段或活动时仅允许动画发生(例如,获取创建时的系统时间,仅允许第一个淡入淡出持续时间毫秒).

我从中创建了动画,只做了一点
修改
,使动画只运行一次

换言之,
动画仅在向下滚动时出现

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

只需扩展适配器,如下所示

public class RankingAdapter extends AnimatedRecyclerView<RankingAdapter.ViewHolder> 
这是一种自动创建动画适配器的方法,如“Basheer AL-MOMANI”

导入android.support.v7.widget.RecyclerView;
导入android.view.view;
导入android.view.ViewGroup;
导入android.view.animation.animation;
导入android.view.animation.ScaleAnimation;
导入java.util.Random;
/**
*由eliaszkubala于2017年2月24日创建。
*/
公共类animatedRecyclView扩展了RecyclView.Adapter{
@凌驾
public T onCreateViewHolder(视图组父级,int-viewType){
返回null;
}
@凌驾
公共无效onBindViewHolder(T holder,内部位置){
设置动画(holder.itemView,位置);
}
@凌驾
public int getItemCount(){
返回0;
}
受保护的int mLastPosition=-1;
受保护的void setAnimation(视图视图到动画,int位置){
如果(位置>mLastPosition){
缩放动画动画=新缩放动画(0.0f,1.0f,0.0f,1.0f,Animation.RELATIVE\u TO\u SELF,0.5f,Animation.RELATIVE\u TO\u SELF,0.5f);
anim.setDuration(new Random().nextInt(501));//使duration随机数介于[0501]之间
视图动画。开始动画(动画);
mLastPosition=位置;
}
}
}

将此方法创建到您的recyclerview适配器中

private void setZoomInAnimation(View view) {
        Animation zoomIn = AnimationUtils.loadAnimation(context, R.anim.zoomin);// animation file 
        view.startAnimation(zoomIn);
    }
最后在onBindViewHolder中添加这行代码


setZoominamination(holder.itemView);

您可以向
RecyclerView
添加
android:LayoutImation=“@anim/rv\u item\u animation”
属性,如下所示:

@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);
}
<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"                                        
    android:layoutAnimation="@anim/layout_animation_fall_down"
    />

仅用XML简化

res/anim/layout\u 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%" />
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500">

    <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"
        />

</set>

res/anim/item\u animation\u fall\u down.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%" />
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500">

    <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"
        />

</set>

在布局和recylcerview中使用,如:

<androidx.recyclerview.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" />

2019年, 我建议将所有项目动画放入ItemAnimator

让我们从在“回收器”视图中声明动画师开始:

with(view.recycler_view) {
adapter = Adapter()
itemAnimator = CustomAnimator()
}
然后声明自定义动画师

class CustomAnimator() : DefaultItemAnimator() {

     override fun animateAppearance(
       holder: RecyclerView.ViewHolder,
       preInfo: ItemHolderInfo?,
       postInfo: ItemHolderInfo): Boolean{} // declare  what happens when a item appears on the recycler view

     override fun animatePersistence(
       holder: RecyclerView.ViewHolder,
       preInfo: ItemHolderInfo,
       postInfo: ItemHolderInfo): Boolean {} // declare animation for items that persist in a recycler view even when the items change

}
与上面的类似,还有一个用于消失
animateDisappearance
、添加
animatedad
、更改
animateChange
和移动
animateMove

一个重要的问题是调用corr
class CustomAnimator() : DefaultItemAnimator() {

     override fun animateAppearance(
       holder: RecyclerView.ViewHolder,
       preInfo: ItemHolderInfo?,
       postInfo: ItemHolderInfo): Boolean{} // declare  what happens when a item appears on the recycler view

     override fun animatePersistence(
       holder: RecyclerView.ViewHolder,
       preInfo: ItemHolderInfo,
       postInfo: ItemHolderInfo): Boolean {} // declare animation for items that persist in a recycler view even when the items change

}
override fun onViewAttachedToWindow(holder: ViewHolder) {
    super.onViewAttachedToWindow(holder)

    setBindAnimation(holder)
}