如何实现RecyclerView Item动画?

这个问题想必有很多人都会讲,我可以用ItemAnimator实现啊,这是RecyclerView官方定义的接口,专门扩展Item动画的,那我为什么要寻求另外一种方法实现呢?因为最近反思了一个问题,其实很多人都有这个思维定律,那就是官方的一定是好的,真的是这样吗?下面我来从另一个角度说明官方的ItemAnimator是真的不好用

ItemAnimator 弃用理由

理由一



  • 第一张图是最牛逼的星星最多的wasabeef/recyclerview-animators,基类有713行代码,你知道这个类打包出来多大吗?有20多kb,相当恐怖的好吗?
  • 第二个是官方提供的默认动画,也是将近700行

理由是:代码过于臃肿

理由二

既然我想用ItemAnimator接口,且官方有一个DefaultItemAnimator,为什么我不能扩展DefaultItemAnimator,而是要实现SimpleItemAnimator,写个700行代码才能够捋明白一个Item的动画?总之,当我知道继承SimpleItemAnimator后,实现的和DefaultItemAnimator几乎一样的时候,我内心是拒绝的,我不想看到这些冗余的代码,也许是我有那么一点点洁癖

理由是:复用率太低,感觉官方根本没当回事(也许是我学习没到位,没有看到它好的地方)

理由三

notifyDataSetChanged不支持ItemAnimator动画,我不讨论这么设计是真的好和坏,但起码它是我不选择ItemAnimator的另一个理由

等等吧,不知道还能吐槽什么了?虽然有这些缺点,可我们总会遇到不得不用的时候,你说呢?

layoutAnimation 弃用理由

这个用的比较少吧,大部分都是在用ItemAnimator,我们直接看个例子,然后再说为什么要弃用它

step1

     android:duration="@integer/anim_duration_medium">

        android:fromYDelta="-20%"        android:toYDelta="0"        android:interpolator="@android:anim/decelerate_interpolator"        />

        android:fromAlpha="0"        android:toAlpha="1"        android:interpolator="@android:anim/decelerate_interpolator"        />

        android:fromXScale="105%"        android:fromYScale="105%"        android:toXScale="100%"        android:toYScale="100%"        android:pivotX="50%"        android:pivotY="50%"        android:interpolator="@android:anim/decelerate_interpolator"        />

step2

<?xml version="1.0" encoding="utf-8"?>    xmlns:android="http://schemas.android.com/apk/res/android"    android:animation="@anim/item_animation_fall_down"    android:delay="15%"    android:animationOrder="normal"    />

step3

int resId = R.anim.layout_animation_fall_down;LayoutAnimationController animation = AnimationUtils.loadLayoutAnimation(ctx, resId);recyclerview.setLayoutAnimation(animation);

很简单对吧,当我运行demo的时候,似乎看起来效果很好哦,可最后我才发现一些问题,我决定不使用它了

理由一

动画只加载第一屏?这个能不能改观我没有深入研究哦,可这样一个效果我也无法忍受,但我上啦的时候,为什么下面未显示的Item动画就没了呢?这就是我弃用的理由

理由二

当我用GridLayoutManger 的时候,我还要在定义一套 layhoutAnimation,虽然只是增加了一个xml文件,可这比起我接下来介绍的实现方案,那就差了一个档次,所以我选择弃用

最简单的Animation动画方案

这个方案的优势:

  • 代码超级简洁
  • 动画的定制度更高,没一个Item都可以轻松的且变着花样的加载动画
  • 可实现预加载动画,可实现更新的动画
  • 轻松实现一个接一个的加载动画
  • 缓存更加轻量级,减少内存开销

缺点:当然也有缺点,这个看具体使用场景的取舍,也许是可以支持的,但目前我还没有想到如何做到。

  • 没有删除动画
  • 没有移动动画

对的目前就这俩。

实现原理

很简单,就是给View加载一个Animation,通过xml配置

实现效果

代码

step1

从下往上移动的动画

<?xml version="1.0" encoding="utf-8"?>    android:duration="@integer/anim_duration_long">        android:interpolator="@android:anim/accelerate_decelerate_interpolator"        android:fromYDelta="50%p"        android:toYDelta="0"        />

        android:fromAlpha="0"        android:toAlpha="1"        android:interpolator="@android:anim/accelerate_decelerate_interpolator"        />

step2

//从零开始计数,用来实现一个接一个的延迟动画(简单点就是:在一个加载一半时,下一个才执行)private var delayPosition = 0//缓存Animation,避免重复loadAnimation,减少开销private val animationArray = SparseArray()//加载xml动画,并放入缓存中private fun loadAnimation(context: Context, @AnimRes itemAnimationRes: Int, key: Int): Animation {    return animationArray[key] ?: AnimationUtils.loadAnimation(context, itemAnimationRes).apply {        animationArray.append(key, this)    }}//清理缓存fun RecyclerView.onDestroy(){    animationArray.clear()}//执行动画fun RecyclerView.ViewHolder.animationWithDelayOffset(    isEnableAnimation: Boolean,    @AnimRes itemAnimationRes: Int,    delayOffset: Int) {    if (isEnableAnimation) {        //清理调之前的动画        itemView.clearAnimation()        //当前item positon        val currentPosition = ++delayPosition        //计算下一个Item需要delay的时间        val delay = currentPosition * delayOffset / 2        itemView.animation =            loadAnimation(itemView.context, itemAnimationRes, currentPosition).apply {               //延迟多久开始执行                startOffset = delay.toLong()                //加载完成后将计数制成零                setAnimationListener(object : Animation.AnimationListener {                    override fun onAnimationRepeat(p0: Animation?) {                    }                    override fun onAnimationEnd(p0: Animation?) {                        delayPosition = 0                    }                    override fun onAnimationStart(p0: Animation?) {                    }                })                //如果已经执行一次才会调用start,因为第一次用AnimationUtils.loadAnimation加载的时候会自动执行一次                if (this.hasEnded()) {                    this.start()                }            }    }}//这个是我的DefaultViewHolder,我可以拿到ViewModel是否是第一次isFirstInit,这样就可以实现只有第一次初始化后才会执行哦fun DefaultViewHolder.firstAnimation(    @AnimRes itemAnimationRes: Int = R.anim.item_animation_from_right,    delayOffset: Int = 200) = animationWithDelayOffset(    getViewModel()?.isFirstInit ?: false,    itemAnimationRes,    delayOffset)//拿到ViewModel是否是第一次isFirstInit,这样就可以实现只有第二次加载执行哦fun DefaultViewHolder.updateAnimation(    @AnimRes itemAnimationRes: Int = R.anim.item_animation_scale) = animation(!(getViewModel()?.isFirstInit ?: false), itemAnimationRes)

代码里有个细节处理《加载完成后将计数制成零》,这里是因为,你第一次进页面的时候,所有的Item的都按照顺序执行完毕后,由于delay数很大,导致你滑动的时候,会出现很久才加载进来的动画哦,这里我是想用handler的postdelay实现,这样就可以做到只要有接着的动画执行,就不会被重制成0,保证下次动画的执行一定是在上一个Item的后面,这样确实是一个问题,也许在我验证够多的场景后就切过去了,嘿嘿。但目前来看,这个效果实现的很满意,慢慢重构和完善。当然我的这种实现方式,确实是比较简单而且效果还不错,既有LayoutAnimation的影子,又有ItemAnimator的功能,岂不是很不错。

step3

应用,一行代码搞定


配置更新时候的动画,一行搞定

感觉到简单了吧,这么顺滑的动画实现,你不想体验下吗?

Demo地址,欢迎体验

https://github.com/ibaozi-cn/RecyclerViewAdapter

接下来会解决什么问题?

这么用难道确实比ItemAnimator好吗?当然会有一些问题吧,比如什么时候需要中断,什么时候需要重新加载,甚至到底什么时候清理掉缓存更合理呢?之后还需要一些更全面的实战来解决这问题,也会借助ItemAnimator的实现原则来考虑当前动画如何做到合理的生命周期管理。

作者

i校长

  • 简书 https://www.jianshu.com/u/77699cd41b28
  • 掘金 https://juejin.im/user/131597127135687
  • 个人网站 http://jetpack.net.cn  、 http://ibaozi.cn

recyclerview item动画_这可能是你见过的迄今为止最简单的RecyclerView Item加载动画...相关推荐

  1. HTML5+CSS3小实例:简单又好看的加载动画效果

    HTML5+CSS3做一个简单又好看的加载动画效果,一个三色圆环转动,再加圆环内部文字转动,效果虽然简单,但第一次看到还是很惊艳的,最主要一点,代码真的超简单的. 效果: 源码: <!DOCTY ...

  2. android 资产管理动图,这可能是你见过的迄今为止最简单的RecyclerView Item加载动画...

    如何实现RecyclerView Item动画? 这个问题想必有很多人都会讲,我可以用ItemAnimator实现啊,这是RecyclerView官方定义的接口,专门扩展Item动画的,那我为什么要寻 ...

  3. CSS 实现加载动画之五-光盘旋转

    今天做的这个动画叫光盘旋转,名字自己取的.动画的效果估计很多人都很熟悉,就是微信朋友圈里的加载动画.做过前面几个动画,发现其实都一个原理,就是如何将动画的元素如何分离出来.这个动画的实现也很简单,关键 ...

  4. css光盘转动,CSS 实现加载动画之五-光盘旋转

    CSS 实现加载动画之五-光盘旋转 今天做的这个动画叫光盘旋转,名字自己取的.动画的效果估计很多人都很熟悉,就是微信朋友圈里的加载动画.做过前面几个动画,发现其实都一个原理,就是如何将动画的元素如何分 ...

  5. 超酷jQuery进度条加载动画集合

    在丰富多彩的网页世界中,进度条加载动画的形式非常多样,有利用gif图片实现的loading动画,也有利用jQuery和CSS3实现的进度加载动画,本文主要向大家介绍很多jQuery和CSS3实现的进度 ...

  6. 【HTML网页前端开发加载动画案例】

    提示:如需转载请联系作者授权才可使用. 目录 前言 一.网页加载动画是什么? 二.案例教学 1.HTML 当我们将css基础操作先做好之后,发现网页并不能完美对应大小,那么我们可以在基础代码定义块内做 ...

  7. 干货!14个最新优质加载动画设计,让等待成为一种享受

    互联网时代,网络"提速"日益频繁,人们打开Web或软件的速度越来越快,一般页面缓冲和加载地过程也是几不可查.然而,在某些情况下,例如软件急需加载大量页面,首页急需加载大量内容,用户 ...

  8. css线条伸缩_CSS3加载动画之线条伸缩

    加载动画之线条伸缩 效果图 思路 通过 3 个线条高度的动态变化实现加载动画,为了突出效果,给线条增加了阴影.对动画而言,keyframes 和 animation 是必不可少的技巧.同时本例中使用了 ...

  9. 7 种最棒的 Vue Loading 加载动画组件测评与推荐 - 穷尽市面上所有加载动画效果(Vue loader)类型

    本文完整版:<7 种最棒的 Vue Loading 加载动画组件测评与推荐> 目录 7 种不同类型的 Vue Loading 加载动画组件 1. Vue Simple Spinner - ...

最新文章

  1. 中国移动手机网络私有网络连接问题解决办法
  2. 窗口不小心拉到任务栏下面,窗口无法拖回桌面的解决办法
  3. 【数据库系统概论】考研第三部分重点分析【3.1】
  4. ZBLOG-ASP2.2如何给图片增加ALT标签说明文字?
  5. python for循环连续输入五个成绩判断等级_Python条件循环判断
  6. JEECG社区公司,招聘全职JAVA工程师(全职)
  7. Java关键字new和newInstance的区别
  8. 【情感分析】基于Aspect的情感分析模型总结(PART IV)
  9. 诺基亚智能手机知识大全
  10. java Math.random()
  11. socks5协议(rfc1928)
  12. xp计算机限制打开u盘,XP系统无法读取u盘的解决设置方法
  13. DDR4时序标准规范(一)
  14. linux下删除文件夹及下面所有文件
  15. java.util.list源码_关于fest-util源码包Collections集合工具类过滤、判空、格式化及复制克隆处理...
  16. Java贪吃蛇暂停怎么做_Java实现贪吃蛇游戏(1小时学会)
  17. 新闻|智链万源CEO董宁受邀参加2019可信区块链峰会,解读溯源行业标准
  18. 如何快速接入直播服务 七牛云企业直播解决方案来了
  19. B2C平台如何实现商户自动分账?
  20. 晋升述职,你真的准备好了吗?

热门文章

  1. mysql dmz_MySQL 中LIMIT的使用详解
  2. php header 404 nginx,ThinkPHP在nginx下怎么设置?路由统统404,疯了~
  3. 架构师基础必备:“腹有诗书气自华”,驰骋一线大厂不是梦,抓紧收藏
  4. java注意的一些细节问题
  5. java中Cookie中文字符乱码问题
  6. mysql 多实例 独立配置文件_三、安装配置多实例MYSQL5.6-多独立配置文件方法
  7. 降维后输入分类器分类时报错_逻辑回归解决多分类方法及其优缺点分析
  8. matlab 价格统计,matlab中的金融数据统计
  9. 爱特php文件管理器2.8_查找「超级蜘蛛池开发者中心 抠:44564876易」安卓应用 - 豌豆荚...
  10. linux dns 内网ip,Ubuntu中ip地址、网关、网络号、DNS等解释