You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过代码将GIF设为Button复合Drawable并实现动效播放

解决Button复合Drawable中GIF无法播放动效的问题

问题原因

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 04:16:07