RecyclerView notifyItem闪烁的问题

简介: 之前我们做点赞,用listview做的话,就是在item实现点击后,写一个scal动画,不过现在都转到RecyclerView,那么要做这种效果于是做了一个notifyItemChanged()的操作,功能都顺利实现,美中不足的是当前Item闪了一下,QA甚至为此提了Bug,一开始以为是图片加载库的问题,之后随着图片加载库从ImageLoader换成Picaso,又换成Glide,这个Bu

之前我们做点赞,用listview做的话,就是在item实现点击后,写一个scal动画,不过现在都转到RecyclerView,那么要做这种效果于是做了一个notifyItemChanged()的操作,功能都顺利实现,美中不足的是当前Item闪了一下,QA甚至为此提了Bug,一开始以为是图片加载库的问题,之后随着图片加载库从ImageLoader换成Picaso,又换成Glide,这个Bug一直如影随形。后来才发现“闪一下”原来是RecyclerView的默认动画,我的代码里有这样一句mRecyclerView.setItemAnimator(new DefaultItemAnimator());原来是这句代码搞的鬼,于是注掉再跑,但并没什么卵用。于是又改成mRecyclerView.setItemAnimator(null);仍然没什么卵用。看来加不加这句,RecyclerView都默认执行了这个动画,看来还有点小麻烦。


before.gif

先来了解下这个RecyclerView的动画吧。

RecyclerView.ItemAnimator

ItemAnimator能够帮助Item实现独立的动画。
ItemAnimator触发于以下三种事件:

某条数据被插入到数据集合中
从数据集合中移除某条数据
更改数据集合中的某条数据

在Android中默认实现了一个DefaultItemAnimator
,我们可以通过以下代码为Item增加动画效果:
recyclerView.setItemAnimator(new DefaultItemAnimator());

在之前的版本中,当数据集合发生改变时,我们通过调用notifyDataSetChanged()来刷新列表,因为这样做会触发列表的重绘,所以并不会出现任何动画效果,但现在我的需求是只改变了当前一个Item的状态,因此需要调用一些以notifyItem*()作为前缀的特殊方法,比如:

向指定位置插入Item
public final void notifyItemInserted(int position)
移除指定位置Item
public final void notifyItemRemoved(int position)
更新指定位置Item
public final void notifyItemChanged(int position)

但是现在的问题就是,调用notifyItem*()方法会触发RecyclerView的默认动画,而这个动画我并不想要,但是似乎并没有合适的办法来屏蔽这个动画,QA甚至认为这是个Bug,需要修复。与同行们交流了下,也有人遇到同样的问题,解决办法居然是调用notifyDataSetChanged()方法来刷新数据,这样就不会有闪一下的动画了。但是这样不就失去使用RecyclerView的优势和意义了吗?

最后我是通过重写RecyclerView的动画来解决这一“Bug”。

public class NoAlphaItemAnimator extends RecyclerView.ItemAnimator {

}

将DefaultItemAnimator类里的代码全部copy到自己写的动画类中,然后做一些修改。

首先找到private void animateChangeImpl(final ChangeInfo changeInfo) {}方法。

找到方法里这两句代码:
1:oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { ... }

2:newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).alpha(1).setListener(new VpaListenerAdapter() { ... }

替换成:
1:oldViewAnim.setListener(new VpaListenerAdapter() { ... }

2newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).setListener(new VpaListenerAdapter() { ... }

也就是说分别去掉上述代码中的alpha(0)alpha(1),然后保存。这个时候基本就打工告成了。最后在自己的RecyclerView中进行如下调用mRecyclerView.setItemAnimator(new NoAlphaItemAnimator());,再跑起来,bug完美解决。




目录
相关文章
|
Java Linux Maven
Docker系列教程11-使用Nexus管理Docker镜像
原文: Nexus简介 Nexus是一个多功能的仓库管理器,是企业常用的私有仓库服务器软件。目前常被用来作为Maven私服、Docker私服。本文基于Nexus 3.5.2-01 版本进行讲解。
4270 0
|
8月前
|
NoSQL Linux Redis
每天百万访问也不怕,Redis帮你搞定UV统计
本文介绍了使用Redis实现高性能UV统计系统的方法。Redis凭借其内存数据库特性,支持毫秒级响应和自动去重,非常适合高并发场景下的访客统计。核心思路是利用Redis的Set数据结构作为"每日签到墙",通过记录用户访问ID实现自动去重,并设置24小时过期时间。文章提供了Python代码示例,展示如何记录用户访问和获取当日UV统计数据,还可扩展实现多页面UV统计。相比传统数据库方案,Redis方案更加轻量高效,是中小型网站实现流量统计的理想选择。
674 0
|
Android开发
利用layer-list和shape实现下划线效果
因为shape如果形状设为line,则是居中的,可以做分割线,但是无法做下划线。 比如我们想为TextView设置一个背景,实现下划线。 需要用layer-list,因为shape的stroke是四周描边的,这里android:left="-4dp"就是指item的drawable(就是shape)从整个画布的-4dp开始绘制, 这样其实显示在画布中的shape就没有左边了,同理,上左右都这么处理就只剩下底边,就实现了下划线效果
730 0
|
Java 数据处理 分布式数据库
Flink中的Exactly-Once语义是什么?请解释其作用和实现原理。
Flink中的Exactly-Once语义是什么?请解释其作用和实现原理。
307 0
UE4/5 使用Sequence录制功能,实现自定义蓝图逻辑的运行
UE4/5 使用Sequence录制功能,实现自定义蓝图逻辑的运行
1076 0
UE4/5 使用Sequence录制功能,实现自定义蓝图逻辑的运行
|
网络协议 网络架构
双点双向重分布导致路由环路,你要怎么解?(上)
双点双向重分布导致路由环路,你要怎么解?
695 1
双点双向重分布导致路由环路,你要怎么解?(上)
|
人工智能 Dart Java
Flutter集成百度语音识别(Android端)实战
Flutter集成百度语音识别(Android端)实战
1586 0
Flutter集成百度语音识别(Android端)实战
实用技巧 | RecyclerView 设置最大高度
实用技巧 | RecyclerView 设置最大高度
|
Linux C# Docker
推荐基于.NetCore一款高性能敏感词检测开源库
一款基于.Net开发的、高性能敏感词工具箱,支持繁简互换、全角半角互换,拼音模糊搜索等功能。功能强大、高性能,秒级检测亿级别的文章。
724 0
推荐基于.NetCore一款高性能敏感词检测开源库
|
安全 Java
Java发送邮件(图片、附件、HTML)
Java发送邮件(图片、附件、HTML)
1200 0
Java发送邮件(图片、附件、HTML)