参照sunhapper的思路,设置Drawable.Callback来刷新TextView,但实际操作中踩了一个大坑:应用是用的Glide来加载图片,奇怪的是即使invalidate掉整个TextView也没法刷新Glide自带的GifDrawable,相对的android-gif-drawable即使没有再次调用Drawable.draw也能很好的刷新。
由于android-gif-drawable是用OpenGL来刷新GIF图片,一开始没敢深究,就把GifDrawable转成android-gif-drawable。后来,打算用CircularProgressDrawable来显示加载进度,这时候Drawable就没法转成android-gif-drawable了。
被迫研究了android-gif-drawable的代码,发现它是创建了一个Bitmap来给OpenGL进行绘制,再在Drawable.onDraw里把Bitmap绘制出来。相对的,GifDrawable是在Drawable.draw里直接绘制,由于Drawable.draw只调用一次,就没能显示动态的图片。
也就是说,在TextView开启硬件加速的情况下,虽然Drawable.draw只被调用一次,但是Bitmap会以引用的形式传递给GPU,修改Bitmap就能在下次绘制时更新图像。
那么我们继承AnimationDrawable来写个Wrapper,它包含一个drawable变量,当然也有一个Bitmap缓存:
1 | var drawable: Drawable? = null |
首先,在每次修改drawable变量时,把原drawable停掉,把Bitmap的大小设置成和drawable一样大,并加上Drawable.Callback:
1 | (this.drawable as? Animatable)?.stop() |
drawableCallback负责在drawable更新的时候刷新Bitmap,并调用容器的invalidate:
1 | fun updateBuffer() { |
最后在draw里把Bitmap绘制出来就完成了:
1 | private val mPaint = Paint(Paint.FILTER_BITMAP_FLAG or Paint.DITHER_FLAG) |