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

在自定义View的onDraw方法中绘制可播放GIF作为底层背景

自定义View底层绘制GIF背景的靠谱方案

别用废弃的Movie类了,换Glide处理GIF帧

Movie类早就被官方废弃,高版本Android里根本找不到对应依赖,直接用Glide库来解码和播放GIF帧就行,步骤如下:

1. 先加Glide依赖

在模块级的build.gradle里的dependencies块中添加:

implementation 'com.github.bumptech.glide:glide:4.16.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'

2. 自定义View的具体实现

写一个继承自View的类,用Glide加载GIF,拿到可动画的Drawable,然后在onDraw里先画GIF背景,再画其他内容:

public class GifBackgroundView extends View {
    private AnimatedDrawable2 gifDrawable;
    private boolean gifLoaded = false;

    public GifBackgroundView(Context context) {
        super(context);
        loadGif();
    }

    public GifBackgroundView(Context context, AttributeSet attrs) {
        super(context, attrs);
        loadGif();
    }

    private void loadGif() {
        // 这里加载assets里的GIF,也可以换成res里的资源ID或者网络链接
        Glide.with(this)
             .asDrawable()
             .load("file:///android_asset/your_bg.gif")
             .addListener(new RequestListener<Drawable>() {
                 @Override
                 public boolean onLoadFailed(GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                     return false;
                 }

                 @Override
                 public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                     if (resource instanceof AnimatedDrawable2) {
                         gifDrawable = (AnimatedDrawable2) resource;
                         // 设置动画循环播放
                         gifDrawable.registerAnimationCallback(new AnimatedDrawable2.AnimationCallback() {
                             @Override
                             public void onAnimationEnd(AnimatedDrawable2 drawable) {
                                 drawable.start();
                             }
                         });
                         gifLoaded = true;
                         invalidate();
                     }
                     return false;
                 }
             })
             .submit();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 先画GIF背景,确保在最底层
        if (gifLoaded && gifDrawable != null) {
            gifDrawable.setBounds(0, 0, getWidth(), getHeight());
            gifDrawable.draw(canvas);
            // 动画运行时,请求下一帧重绘
            if (gifDrawable.isRunning()) {
                postInvalidateOnAnimation();
            }
        }

        // 这里写你要画的上层内容,比如文字、图形
        Paint textPaint = new Paint();
        textPaint.setColor(Color.WHITE);
        textPaint.setTextSize(60f);
        textPaint.setTextAlign(Paint.Align.CENTER);
        canvas.drawText("我是上层内容", getWidth()/2f, getHeight()/2f, textPaint);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        // 页面显示时启动动画
        if (gifDrawable != null) {
            gifDrawable.start();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        // 页面销毁时停止动画,避免内存泄漏
        if (gifDrawable != null) {
            gifDrawable.stop();
        }
    }
}

3. 要注意的几个点

  • 把你的GIF放在正确的位置,比如assets文件夹,或者用R.drawable.your_gif作为加载路径
  • 一定要先画GIF,再画其他内容,这样GIF才会在底层
  • 在View绑定和解绑窗口时启停动画,防止内存浪费

之前崩溃的大概率原因

你之前按SO方案崩溃,多半是这几个问题:

  • 用了废弃的Movie类,高版本Android不兼容
  • GIF资源路径写错,导致空指针
  • 没处理好动画帧的重绘,把UI线程搞崩了

用上面Glide的方案就能避开这些坑,因为Glide已经帮你做好了各版本的适配。

内容的提问来源于stack exchange,提问作者Rishabh Gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 01:20:23