RecycleView的Item Animator动画
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动画相关推荐
- Android添加item动画,RecyclerView基础篇-Item添加动画
Android_Banner.jpg 简介 本节中我们介绍下给RecyclerView中的Item添加动画. 添加的动画,分为,在打开列表时有Item的展示动画,当滑动的时候没有动画 和打开列表滑动时 ...
- Android recycleview使用详解,recycleview实现九宫格布局即横向排列,recycleview设置item占位数量大号item或小号item
1.添加recycleview依赖 compile('com.android.support:recyclerview-v7:25.1.1') {force = true } 2.item.xml & ...
- 用Unity的Animation播放Animator动画Clip
简单的动画,其实不需要Animator动画状态机管理,用Animation播放效率更高,但可能由于历史遗留问题,或网上下载的第三方资源,得到的是Animator资源,可以在Clip的Debug试图下, ...
- Cartoon Animator动画制作软件CTA自动保存项目小工具
大家都知道Cartoon Animator动画软件总是会无辜闪退 好不容易K了很多帧,然后崩溃立马回到解放前. 做了这个小工具暂时解决一下燃眉之急!!!! 下载地址: https://download ...
- 对RecyclerView Item做动画
对RecyclerView Item做动画 对RecyclerView Item做动画,刚刚开始研究的时候一些坑,在这里把一些设计思路分享出去 添加动态位移,静态位移,缩放等动画,保证了动画状态的平滑 ...
- 【Unity3D小技巧】Unity3D中Animation和Animator动画的播放、暂停、倒放控制
推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦. 一.前言 ...
- 『ANDROID』android animator 动画
原文地址:android animator 动画 animator 动画 动画的作用是让UI有动感, 看上去时尚. Android中动画分两种方式: 一种方式是补间动画Tween Animation, ...
- android animator 动画
animator 动画 动画的作用是让UI有动感, 看上去时尚. Android中动画分两种方式: 一种方式是补间动画Tween Animation,就是说你定义一个开始和结束,中间的部分由程序运算得 ...
- 【Unity3D】Animator动画播放时卡死在第一帧BUG系列
常见因素: 1.Animator在Update或其他每帧执行的协程或方法里疯狂被代码调用. 2.Animator动画播放事件会再次调用Animator动画播放. 3.Animator状态机切换问题,A ...
最新文章
- 三层交换机原理:01路由器如何隔离广播域?
- I2C和SPI总线优缺点对比
- 字符串插入_动态规划----字符串编辑最小距离
- 计算机线性输入录音原理,耳机输出的模拟信号-怎样把声音通过线路录入电脑?比方说,收音机的耳机输出孔,接线(串 爱问知识人...
- linux 之间 copy 传输文件方法:ftp、samba、sftp、scp、sz/rz
- GitHub或正式登陆中国!拟在中国设立分公司
- 新闻媒体是怎样使用计算机的,计算机技术在新闻上的应用
- JavaScript中的数字型
- webmin安装_如何在Ubuntu 18.04上安装Webmin
- HDU 4335 What is N?(指数循环节)题解
- django-admin源码解析
- 比navicat还好用的mysql可视化工具
- 专访时速云|容器云“老兵”与云原生“新战场”
- 【知识管理】知识管理系统功能构件简介
- 妙用AccessibilityService黑科技实现微信自动加好友拉人进群聊
- 0.96寸OLED(SSD1306)屏幕显示(一)——基础功能介绍
- 浏览器无法访问某个网站,其他网站都正常
- Cookie经典案例—实现显示用户上次服务时间的显示
- openstack研究意义_OpenStack如何推动CERN的研究
- USB2.0传输带宽
热门文章
- 第八周PLC编程练习
- 【piu~】制作一只变形小鸡~
- 《移山之道-VSTS软件开发指南》---读书笔记
- 在DialogFragment中显示大图片
- python从html拿到数据,python - 使用BeautifulSoup和Python从HTML文件中提取数据 - 堆栈内存溢出...
- mysql view 子查询_mysql – View的SELECT包含FROM子句中的子查询
- java 中反射的使用_java中反射的基本使用
- element ui 图片控件 排序_vuedraggable+element ui实现页面控件拖拽排序效果
- matlab 矩阵引用,MATLAB矩阵生成、引用
- 高甜预警|甜齁你的情人节促销海报设计模板