天天看点

RecyclerView notifyItem闪烁的问题

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

RecyclerView notifyItem闪烁的问题

before.gif

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

recyclerview.itemanimator

itemanimator能够帮助item实现独立的动画。

itemanimator触发于以下三种事件:

某条数据被插入到数据集合中

从数据集合中移除某条数据

更改数据集合中的某条数据

在android中默认实现了一个defaultitemanimator

,我们可以通过以下代码为item增加动画效果:

<code>recyclerview.setitemanimator(new defaultitemanimator());</code>

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

向指定位置插入item

<code>public final void notifyiteminserted(int position)</code>

移除指定位置item

<code>public final void notifyitemremoved(int position)</code>

更新指定位置item

<code>public final void notifyitemchanged(int position)</code>

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

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

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

首先找到<code>private void animatechangeimpl(final changeinfo changeinfo) {}</code>方法。

找到方法里这两句代码:

1:<code>oldviewanim.alpha(0).setlistener(new vpalisteneradapter() { ... }</code>

2:<code>newviewanimation.translationx(0).translationy(0).setduration(getchangeduration()).alpha(1).setlistener(new vpalisteneradapter() { ... }</code>

替换成:

1:<code>oldviewanim.setlistener(new vpalisteneradapter() { ... }</code>

2<code>newviewanimation.translationx(0).translationy(0).setduration(getchangeduration()).setlistener(new vpalisteneradapter() { ... }</code>

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

下一篇: squid

继续阅读