RecyclerView能够通过mRecyclerView.setItemAnimator(ItemAnimator animator)设置添加、删除、移动、改变的动画效果

RecyclerView提供了默认的ItemAnimator实现类:DefaultItemAnimator。如果没有特殊的需求,默认使用这个动画即可。

// 设置Item添加和移除的动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());

下面就添加一下删除和添加Item的动作。在Adapter里面添加方法

public void addNewItem() {if(mData == null) {mData = new ArrayList<>();}mData.add(0, "new Item");更新数据集不是用adapter.notifyDataSetChanged()而是notifyItemInserted(position)与notifyItemRemoved(position) 否则没有动画效果。 notifyItemInserted(0);
}public void deleteItem() {if(mData == null || mData.isEmpty()) {return;}mData.remove(0);notifyItemRemoved(0);
}

添加事件的处理。

public void onClick(View v) {int id = v.getId();if(id == R.id.rv_add_item_btn) {mAdapter.addNewItem();// 由于Adapter内部是直接在首个Item位置做增加操作,增加完毕后列表移动到首个Item位置mLayoutManager.scrollToPosition(0);} else if(id == R.id.rv_del_item_btn){mAdapter.deleteItem();// 由于Adapter内部是直接在首个Item位置做删除操作,删除完毕后列表移动到首个Item位置mLayoutManager.scrollToPosition(0);}
}

准备工作完毕后,来看一下运行的效果。

DefaultItemAnimator源码分析

这里我们通过分析DefaultItemAnimator的源码来介绍如何自定义Item Animator。

DefaultItemAnimator继承自SimpleItemAnimator,SimpleItemAnimator继承自ItemAnimator。

首先我们介绍ItemAnimator类的几个重要方法

  • animateAppearance(): 当ViewHolder出现在屏幕上时被调用(可能是add或move)。
  • animateDisappearance(): 当ViewHolder消失在屏幕上时被调用(可能是remove或move)。
  • animatePersistence(): 在没调用notifyItemChanged()notifyDataSetChanged()的情况下布局发生改变时被调用。
  • animateChange(): 在显式调用notifyItemChanged()notifyDataSetChanged()时被调用。
  • runPendingAnimations(): RecyclerView动画的执行方式并不是立即执行,而是每帧执行一次,比如两帧之间添加了多个Item,则会将这些将要执行的动画Pending住,保存在成员变量中,等到下一帧一起执行。该方法执行的前提是前面animateXxx()返回true。
  • isRunning(): 是否有动画要执行或正在执行。
  • dispatchAnimationsFinished(): 当全部动画执行完毕时被调用。

上面的方法比较难懂,不过没关系,因为Android提供了SimpleItemAnimator类(继承自ItemAnimator),该类提供了一系列更易懂的API,在自定义Item Animator时只需要继承SimpleItemAnimator即可:

  • animateAdd(ViewHolder holder): 当Item添加时被调用。
  • animateMove(ViewHolder holder, int fromX, int fromY, int toX, int toY): 当Item移动时被调用。
  • animateRemove(ViewHolder holder): 当Item删除时被调用。
  • animateChange(ViewHolder oldHolder, ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop): 当显式调用notifyItemChanged()notifyDataSetChanged()时被调用。

对于以上四个方法,注意两点:

  • 当Xxx动画开始执行前(在runPendingAnimations()中)需要调用dispatchXxxStarting(holder),执行完后需要调用dispatchXxxFinished(holder)
  • 这些方法的内部实际上并不是书写执行动画的代码,而是将需要执行动画的Item全部存入成员变量中,并且返回值为true,然后在runPendingAnimations()中一并执行。

DefaultItemAnimator类是RecyclerView提供的默认动画类。我们通过阅读该类源码学习如何自定义Item Animator。我们先看DefaultItemAnimator的成员变量

private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<>();//存放下一帧要执行的一系列add动画
ArrayList<ArrayList<ViewHolder>> mAdditionsList = new ArrayList<>();//存放正在执行的一批add动画
ArrayList<ViewHolder> mAddAnimations = new ArrayList<>(); //存放当前正在执行的add动画private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>();
ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>();private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>();
ArrayList<ViewHolder> mMoveAnimations = new ArrayList<>();private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>();
ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>();
ArrayList<ViewHolder> mChangeAnimations = new ArrayList<>();

DefaultItemAnimator实现了SimpleItemAnimator的animateAdd()方法,该方法只是将该item添加到mPendingAdditions中,等到runPendingAnimations()中执行。

public boolean animateAdd(final ViewHolder holder) {resetAnimation(holder);  //重置清空所有动画ViewCompat.setAlpha(holder.itemView, 0); //将要做动画的View先变成透明mPendingAdditions.add(holder);return true;
}

接着看runPendingAnimations()的实现,该方法是执行remove,move,change,add动画,执行顺序为:remove动画最先执行,随后move和change并行执行,最后是add动画。为了简化,我们将remove,move,change动画执行过程省略,只看执行add动画的过程,如下:

public void runPendingAnimations() {//1、判断是否有动画要执行,即各个动画的成员变量里是否有值。//2、执行remove动画//3、执行move动画//4、执行change动画,与move动画并行执行//5、执行add动画if (additionsPending) {final ArrayList<ViewHolder> additions = new ArrayList<>();additions.addAll(mPendingAdditions);mAdditionsList.add(additions);mPendingAdditions.clear();Runnable adder = new Runnable() {@Overridepublic void run() {for (ViewHolder holder : additions) {animateAddImpl(holder);  //***** 执行动画的方法 *****}additions.clear();mAdditionsList.remove(additions);}};if (removalsPending || movesPending || changesPending) {long removeDuration = removalsPending ? getRemoveDuration() : 0;long moveDuration = movesPending ? getMoveDuration() : 0;long changeDuration = changesPending ? getChangeDuration() : 0;long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);View view = additions.get(0).itemView;ViewCompat.postOnAnimationDelayed(view, adder, totalDelay); //等remove,move,change动画全部做完后,开始执行add动画}}
}

为了防止在执行add动画时外面有新的add动画添加到mPendingAdditions中,从而导致执行add动画错乱,这里将mPendingAdditions的内容移动到局部变量additions中,然后遍历additions执行动画。

runPendingAnimations()中,animateAddImpl()是执行add动画的具体方法,其实就是将itemView的透明度从0变到1(在animateAdd()中已经将view的透明度变为0),实现如下:

void animateAddImpl(final ViewHolder holder) {final View view = holder.itemView;final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);mAddAnimations.add(holder);animation.alpha(1).setDuration(getAddDuration()).setListener(new VpaListenerAdapter() {@Overridepublic void onAnimationStart(View view) {dispatchAddStarting(holder);  //在开始add动画前调用}@Overridepublic void onAnimationCancel(View view) {ViewCompat.setAlpha(view, 1);}@Overridepublic void onAnimationEnd(View view) {animation.setListener(null);dispatchAddFinished(holder); //在结束add动画后调用mAddAnimations.remove(holder);if (!isRunning()) {dispatchAnimationsFinished(); //结束所有动画后调用}}}).start();
}

开源动画recyclerview-animators

从DefaultItemAnimator类的实现来看,发现自定义Item Animator好麻烦,需要继承SimpleItemAnimator类,然后实现一堆方法。
别急,recyclerview-animators解救你,原因如下:

  • 首先,recyclerview-animators提供了一系列的Animator,比如FadeInAnimator,ScaleInAnimator。
  • 其次,如果该库中没有你满意的动画,该库提供了BaseItemAnimator类,该类继承自SimpleItemAnimator,进一步封装了自定义Item Animator的代码,使得自定义Item Animator更方便,你只需要关注动画本身。如果要实现DefaultItemAnimator的代码,只需要以下实现:
public class DefaultItemAnimator extends BaseItemAnimator {public DefaultItemAnimator() {}public DefaultItemAnimator(Interpolator interpolator) {mInterpolator = interpolator;}@Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {ViewCompat.animate(holder.itemView).alpha(0).setDuration(getRemoveDuration()).setListener(new DefaultRemoveVpaListener(holder)).setStartDelay(getRemoveDelay(holder)).start();}@Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {ViewCompat.setAlpha(holder.itemView, 0); //透明度先变为0}@Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {ViewCompat.animate(holder.itemView).alpha(1).setDuration(getAddDuration()).setListener(new DefaultAddVpaListener(holder)).setStartDelay(getAddDelay(holder)).start();}
}

是不是比继承SimpleItemAnimator方便多了。

局部刷新闪屏问题解决

对于RecyclerView的Item Animator,有一个常见的坑就是“闪屏问题”。
这个问题的描述是:当Item视图中有图片和文字,当更新文字并调用notifyItemChanged()时,文字改变的同时图片会闪一下。这个问题的原因是当调用notifyItemChanged()时,会调用DefaultItemAnimator的animateChangeImpl()执行change动画,该动画会使得Item的透明度从0变为1,从而造成闪屏。

解决办法很简单,在rv.setAdapter()之前调用((SimpleItemAnimator)rv.getItemAnimator()).setSupportsChangeAnimations(false)禁用change动画

RecycleView的Item Animator动画相关推荐

  1. Android添加item动画,RecyclerView基础篇-Item添加动画

    Android_Banner.jpg 简介 本节中我们介绍下给RecyclerView中的Item添加动画. 添加的动画,分为,在打开列表时有Item的展示动画,当滑动的时候没有动画 和打开列表滑动时 ...

  2. Android recycleview使用详解,recycleview实现九宫格布局即横向排列,recycleview设置item占位数量大号item或小号item

    1.添加recycleview依赖 compile('com.android.support:recyclerview-v7:25.1.1') {force = true } 2.item.xml & ...

  3. 用Unity的Animation播放Animator动画Clip

    简单的动画,其实不需要Animator动画状态机管理,用Animation播放效率更高,但可能由于历史遗留问题,或网上下载的第三方资源,得到的是Animator资源,可以在Clip的Debug试图下, ...

  4. Cartoon Animator动画制作软件CTA自动保存项目小工具

    大家都知道Cartoon Animator动画软件总是会无辜闪退 好不容易K了很多帧,然后崩溃立马回到解放前. 做了这个小工具暂时解决一下燃眉之急!!!! 下载地址: https://download ...

  5. 对RecyclerView Item做动画

    对RecyclerView Item做动画 对RecyclerView Item做动画,刚刚开始研究的时候一些坑,在这里把一些设计思路分享出去 添加动态位移,静态位移,缩放等动画,保证了动画状态的平滑 ...

  6. 【Unity3D小技巧】Unity3D中Animation和Animator动画的播放、暂停、倒放控制

    推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦. 一.前言 ...

  7. 『ANDROID』android animator 动画

    原文地址:android animator 动画 animator 动画 动画的作用是让UI有动感, 看上去时尚. Android中动画分两种方式: 一种方式是补间动画Tween Animation, ...

  8. android animator 动画

    animator 动画 动画的作用是让UI有动感, 看上去时尚. Android中动画分两种方式: 一种方式是补间动画Tween Animation,就是说你定义一个开始和结束,中间的部分由程序运算得 ...

  9. 【Unity3D】Animator动画播放时卡死在第一帧BUG系列

    常见因素: 1.Animator在Update或其他每帧执行的协程或方法里疯狂被代码调用. 2.Animator动画播放事件会再次调用Animator动画播放. 3.Animator状态机切换问题,A ...

最新文章

  1. 三层交换机原理:01路由器如何隔离广播域?
  2. I2C和SPI总线优缺点对比
  3. 字符串插入_动态规划----字符串编辑最小距离
  4. 计算机线性输入录音原理,耳机输出的模拟信号-怎样把声音通过线路录入电脑?比方说,收音机的耳机输出孔,接线(串 爱问知识人...
  5. linux 之间 copy 传输文件方法:ftp、samba、sftp、scp、sz/rz
  6. GitHub或正式登陆中国!拟在中国设立分公司
  7. 新闻媒体是怎样使用计算机的,计算机技术在新闻上的应用
  8. JavaScript中的数字型
  9. webmin安装_如何在Ubuntu 18.04上安装Webmin
  10. HDU 4335 What is N?(指数循环节)题解
  11. django-admin源码解析
  12. 比navicat还好用的mysql可视化工具
  13. 专访时速云|容器云“老兵”与云原生“新战场”
  14. 【知识管理】知识管理系统功能构件简介
  15. 妙用AccessibilityService黑科技实现微信自动加好友拉人进群聊
  16. 0.96寸OLED(SSD1306)屏幕显示(一)——基础功能介绍
  17. 浏览器无法访问某个网站,其他网站都正常
  18. Cookie经典案例—实现显示用户上次服务时间的显示
  19. openstack研究意义_OpenStack如何推动CERN的研究
  20. USB2.0传输带宽

热门文章

  1. 第八周PLC编程练习
  2. 【piu~】制作一只变形小鸡~
  3. 《移山之道-VSTS软件开发指南》---读书笔记
  4. 在DialogFragment中显示大图片
  5. python从html拿到数据,python - 使用BeautifulSoup和Python从HTML文件中提取数据 - 堆栈内存溢出...
  6. mysql view 子查询_mysql – View的SELECT包含FROM子句中的子查询
  7. java 中反射的使用_java中反射的基本使用
  8. element ui 图片控件 排序_vuedraggable+element ui实现页面控件拖拽排序效果
  9. matlab 矩阵引用,MATLAB矩阵生成、引用
  10. 高甜预警|甜齁你的情人节促销海报设计模板