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

如何实现RecyclerView Item动画?

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

ItemAnimator 弃用理由

理由一

7ff84ba02899720f58cebbe945033a89.png
77c1acbad53cca77673b8a61e46ee002.png
  • 第一张图是最牛逼的星星最多的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配置

实现效果

701e82c6273195df461cc1d82218e8e6.gif

代码

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

应用,一行代码搞定

d8f75e9c37f65f75abc6140f7252b92f.png

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

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

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

30655d213ee4f6e0727d8e67cec8a323.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/538266.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VBoxManage: error: Nonexistent host networking interface, name 'vboxnet0' (VERR_INTERNAL_ERROR)

错误&#xff1a; VBoxManage: error: Nonexistent host networking interface, name vboxnet0 (VERR_INTERNAL_ERROR) 原因&#xff1a; 原来配置的网卡发生了变更&#xff0c;找不到了&#xff0c;启动失败。 解决方法&#xff1a; 第一步&#xff0c;命令&#xff1a; V…

esp32 嵌入式linux,初体验乐鑫 ESP32 AT 指令-嵌入式系统-与非网

乐鑫 AT 固件初体验初步体验 AT 指令下 TCP 数传&#xff0c;为了验证 AT 命令解析器。前往乐鑫官网 下载最新版本 AT 固件和 AT 指令集手册。硬件准备本文使用乐鑫的 ESP-WROOM-32(ESP-WROOM-32 是 ESP32-WROOM-32 的曾用名)模块&#xff0c;4MB Flash&#xff0c;无 PSRAM。E…

主机ping不通Virtualbox里的虚拟机

在redhat上安装了VirtualBox&#xff0c;虚拟了三台Linux机器。 宿主机网卡更换过了。三台虚拟机无法启动了&#xff0c;搭建虚拟机的运维离职了。 VirtualBox的图形界面坏了&#xff0c;启动不了。只能用命令行&#xff0c;今天时间就花在命令行上了。 第一个问题是&#xf…

Git之原有基础开发新功能

场景描述 当一个项目已经上线&#xff0c;同时又在原有基础上新增功能模块&#xff0c;于是乎就要在原有代码的基础上进行开发&#xff0c;在新增模块功能的开发的过程中&#xff0c;项目发现了一个紧急Bug&#xff0c;需要修复。操作流程如下&#xff1a; -------------------…

os.popen read()报编码错误_数据科学家易犯的十大编码错误,你中招了吗?

选自 Medium作者&#xff1a;Norm Niemer机器之心编译参与&#xff1a;李诗萌、王淑婷数据科学家比软件工程师擅长统计&#xff0c;又比统计学家擅长软件工程。听起来牛逼轰轰&#xff0c;事实却是&#xff0c;许多数据科学家有统计学背景&#xff0c;却没有什么软件工程方面的…

linux怎么添加工作组,linux 用户与工作组

在linux 里面&#xff0c;用户的编号UID &#xff0c;也就是用户的ID号。工作组的编号为GID 也就是工作组的ID 号 。1、用户的分类超级用户&#xff1a;root用户&#xff0c;系统安装过程中自动创建&#xff0c;UID 为0。普通用户&#xff1a;操作权限受到限制的用户id在 500-6…

MySQL5.7.12新密码登录方式及密码策略

原文链接&#xff1a;http://www.cnblogs.com/jonsea/p/5510219.html --------------------------------------------------------------------------- 松门一枝花补充 最简单的方法&#xff1a; 1、配置文件中把密码策略关了。本文中间部分有介绍。 2、重启服务 3、用my…

记一次,jvm 内存溢出

1、什么是内存泄漏内存泄漏是指&#xff0c;有未被释放的java对象&#xff0c;一直停留在内存中。GCRoot 无法追踪到此对象&#xff0c;导致此对象无法被回收。 2、什么是内存溢出内存溢出是指&#xff0c;java程序创建对象需要内存&#xff0c;但是却没有内存可用了&#xff0…

钻石指标和完美的计算

钻石的高度计算公式为&#xff1a;钻石的高度直径的三次方&#xff08;单位毫米&#xff09;0.00366(允许有0.03克拉的误差)例如&#xff0c;0.5克拉的钻石直径是5.01毫米&#xff0c;则它的高为&#xff1a;5.01*5.01*5.01*0.003660.46说明0.5克拉的钻石直径只有0.46克拉钻石的…

Spark应用日志级别设置

Spark-core包设置默认的日志级别为info&#xff0c;所以我们才看到一大堆日志信息。 开发的时候&#xff0c;把print的日志掩盖了。 方法一&#xff1a; 代码中设置日志级别 JavaSparkContext contextnew JavaSparkContext(conf); context.setLogLevel("warn"); 方…

linux find 按类型查找,Linux find查找find命令详解

玩蛇网推荐图文教程&#xff1a;python 列表Linux命令有很多&#xff0c;今天要介绍的是常用的基础命令中的find命令。find是Linux系统管理员所喜爱用的必备工具命令之一&#xff0c;它的作用是可以很轻松地找到你想要的文件&#xff0c;一个命令就可以在众多文件中找到你的目标…

window安装gcc编译器

在使用 GraphLab Create 时&#xff0c;导入包失败&#xff0c;提示libs没有的导入&#xff0c;而这些libs的编译是需要gcc。 1、访问&#xff1a;http://www.mingw.org/ 下载。 2、双击安装 3、安装好后会弹出下面的组件安装界面 3、找到mingw32-gcc-g&#xff08;注意cl…

element表格实现树形全选_很实用!word中全选的快捷键介绍及使用方法

全选快捷键可以提高我们在操作word时工作效率&#xff0c;在操作Word2003中怎么对文档中的文字进行全选呢?下面为大家提供几种全选的方法&#xff0c;绝对好用。Word怎样全选?方法一、使用Word全选快捷键“CtrlA”进行全选(也适用于电子表格);方法二、展开菜单栏中的“编辑”…

linux 视频编辑 ffmpeg,ffmpeg转码视频真的好用!(ffmpeg的简单使用方法)

说明转码和编辑视频今天用Android Studio(后面简称AS)里的模拟器给系统录屏&#xff0c;用来展示OpenGL可视化的东西&#xff0c;打算上传B站&#xff0c;后来发现AS只能保存webm格式和GIF格式的视频&#xff0c;并且文件体积巨大&#xff0c;视频图像也是顺时针旋转的。没办法…

requests库入门09-OAUTH认证

实际登陆中&#xff0c;认证用到的token会变的&#xff0c;不过可以在GIthub设置一个私人token。 如图&#xff0c;登录GIthub&#xff0c;然后用户下面选择Settings/Developer settings/Personal access tokens,点击Generate new token&#xff0c;然后随便输个描述&#xff0…

深入了解HashMap

什么是hash&#xff1f;哈希算法将任意长度的二进制值映射为较短的固定长度的二进制值&#xff0c;这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母&#xff0c;随后的哈希都将产生不同的值。要找…

snort入侵检测系统下载Linux,入侵检测系统Snort 2.9.0.2 发布

Snort 是一个免费的、跨平台的软件包&#xff0c;用作监视小型 TCP/IP 网的嗅探器、日志记录、侵入探测器。Snort 是全世界上使用最广泛的入侵预防与侦测软件。Snort 有三种工作模式&#xff1a;嗅探器、数据包记录器、网络入侵检测系统。嗅探器模式仅仅是从网络上读取数据包并…

linux shmmax单位,Linux核心参数Shmmax,shmall,shmni

Linux 下核心参数调整kernel.shmmaxshmmax是核心参数中最重要的参数之一&#xff0c;用于定义单个共享内存段的最大值&#xff0c;shmmax设置应足够大&#xff0c;能在一个共享内存段下容纳下整个的SGA&#xff0c;设置的过低可能会导致需要创建多个共享内存段&#xff0c;可能…

Failed to find Build Tools revision 26.0.1

Error:A problem occurred configuring project :app. > Failed to find Build Tools revision 26.0.1 在build.gradle 中buildToolsVersion 如何修改。看本地安装了哪些版本的 进入文件夹Android SDK 目录下build-tools&#xff0c;修改为里面有的版本

小学数学动画 android,小学数学动画教学下载-小学数学动画 安卓版v5.0-pc6手机下载...

小学数学动画教学软件是一款能让孩子爱上数学的客户端应用&#xff0c;小学数学动画app以动画的形式带领孩子学习数学知识以及各类公式原理&#xff0c;测底掌握数学方法。功能介绍小学数学动画通过形象、生动、清楚、易懂的触摸动画向你解释小学数学知识和原理(小学数学原理和…