参照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) |