百度我的网站,免费建设外贸网站,内丘网站建设,php开发的大型网站有哪些如何实现RecyclerView Item动画#xff1f; 这个问题想必有很多人都会讲#xff0c;我可以用ItemAnimator实现啊#xff0c;这是RecyclerView官方定义的接口#xff0c;专门扩展Item动画的#xff0c;那我为什么要寻求另外一种方法实现呢#xff1f;因为最近反思了一个问… 如何实现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:durationinteger/anim_duration_medium android:fromYDelta-20% android:toYDelta0 android:interpolatorandroid:anim/decelerate_interpolator / android:fromAlpha0 android:toAlpha1 android:interpolatorandroid:anim/decelerate_interpolator / android:fromXScale105% android:fromYScale105% android:toXScale100% android:toYScale100% android:pivotX50% android:pivotY50% android:interpolatorandroid:anim/decelerate_interpolator /step2?xml version1.0 encodingutf-8? xmlns:androidhttp://schemas.android.com/apk/res/android android:animationanim/item_animation_fall_down android:delay15% android:animationOrdernormal /step3int 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 version1.0 encodingutf-8? android:durationinteger/anim_duration_long android:interpolatorandroid:anim/accelerate_decelerate_interpolator android:fromYDelta50%p android:toYDelta0 / android:fromAlpha0 android:toAlpha1 android:interpolatorandroid: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