如何通过代码将GIF设为Button复合Drawable并实现动效播放
问题原因
Android原生的Drawable.createFromStream()方法仅会加载GIF的第一帧静态画面,并不会自动处理GIF的帧动画逻辑,所以设置后只会显示静态图。
解决方案
方法一:原生实现(无需第三方库)
自定义一个GifDrawable继承自Drawable,利用Movie类解析并播放GIF帧动画:
public class GifDrawable extends Drawable implements Runnable { private final Movie mMovie; private final int mDuration; private long mStartTime; private boolean mIsRunning = true; public GifDrawable(InputStream inputStream) { mMovie = Movie.decodeStream(inputStream); mDuration = mMovie.duration(); } @Override public void draw(@NonNull Canvas canvas) { long now = SystemClock.uptimeMillis(); if (mStartTime == 0) { mStartTime = now; } if (mDuration > 0) { long elapsed = now - mStartTime; int frame = (int) ((elapsed % mDuration) * mMovie.width() / mDuration); mMovie.setTime(frame); } mMovie.draw(canvas, 0, 0); if (mIsRunning) { invalidateSelf(); } } @Override public void setAlpha(int alpha) {} @Override public void setColorFilter(@Nullable ColorFilter colorFilter) {} @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } @Override public int getIntrinsicWidth() { return mMovie.width(); } @Override public int getIntrinsicHeight() { return mMovie.height(); } @Override public void run() { invalidateSelf(); if (mIsRunning) { scheduleSelf(this, SystemClock.uptimeMillis() + 1000 / 30); } } public void start() { mIsRunning = true; mStartTime = SystemClock.uptimeMillis(); scheduleSelf(this, mStartTime); } public void stop() { mIsRunning = false; unscheduleSelf(this); } }
修改原代码使用这个自定义Drawable:
try { InputStream inputStream = context.getAssets().open("test.gif"); GifDrawable gifDrawable = new GifDrawable(inputStream); button.setCompoundDrawablesWithIntrinsicBounds(gifDrawable, null, null, null); gifDrawable.start(); // 启动动画 } catch (IOException e) { e.printStackTrace(); }
方法二:使用Glide库(推荐)
如果项目已引入Glide,可直接用它处理GIF动画:
先确保添加Glide依赖(版本以最新稳定版为准):
implementation 'com.github.bumptech.glide:glide:4.16.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
然后编写加载代码:
Glide.with(context) .asGif() .load("file:///android_asset/test.gif") .into(new CustomTarget<Drawable>() { @Override public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) { button.setCompoundDrawablesWithIntrinsicBounds(resource, null, null, null); } @Override public void onLoadCleared(@Nullable Drawable placeholder) {} });
注意事项
- 原生
Movie类在Android 28及以上部分场景存在兼容性问题,适合简单需求场景。 - Glide方法更稳定,还支持缓存、缩放等优化,适合实际项目使用。
内容的提问来源于stack exchange,提问作者user17802442
相关产品推荐
相关产品推荐

