android自定义Drawable显示Gif

在这里插入图片描述
效果图如上。
大家好,最近项目中需要用到gif动画显示,所以就着手研究了下gif的动画显示。
原理主要就是使用Movie的功能,先来看下这个类的主要几个方法:

public class Movie {
    public native int width();
    public native int height();
    public native boolean isOpaque();
    public native int duration();
}

Movie有长、宽以及时长,感觉像是表达电影的一个类。不过gif的原理类似电影,故也能应用加载gif,然后播放gif。为了使用方便,就直接吧这个功能做成了一个自定义drawable-GifDrawable。
GifDrawable即可以加载res资源文件,也可以从加载输入流,所以使用方便。因为比较简单,故直接上源码不多说了。

package com.hai.dialdemo;

import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Movie;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RawRes;
import androidx.annotation.UiThread;

import java.io.InputStream;

/**
 * load a gif into drawable,compatible with < api28,after >= api28 ,AnimatedImageDrawable is recommended.
 */
public class GifDrawable extends Drawable {
    private static final String TAG = "GifDrawable";
    private static final int DEFAULT_MOVIE_DURATION = 1000;

    private static final int GIF_TYPE_ID = 0X10;
    private static final int GIF_TYPE_IS = 0X11;

    private Handler mHandler = new Handler(Looper.getMainLooper());
    private Listener mListener;

    private Movie mMovie;
    private int mGifType;
    private Resources mResources;
    private InputStream mIs;
    private int mResId;
    private long mTimeStart;
    private long mTimeCurrent;

    public GifDrawable() {
    }

    public GifDrawable(Resources res, int resId) {
        this.mResources = res;
        this.mResId = resId;
        mGifType = GIF_TYPE_ID;
        init();
    }

    public GifDrawable(@NonNull InputStream is) {
        this.mIs = is;
        mGifType = GIF_TYPE_IS;
        init();
    }

    public InputStream getIs() {
        return mIs;
    }

    public void setIs(InputStream mIs) {
        this.mIs = mIs;
        mGifType = GIF_TYPE_IS;
        init();
    }

    public int getResId() {
        return mResId;
    }

    public void setResId(Resources res, int resId) {
        this.mResources = res;
        this.mResId = resId;
        mGifType = GIF_TYPE_ID;
        init();
    }

    private void init() {
        AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
                if (mGifType == GIF_TYPE_ID) {
                    if (mResources != null && mResId > 0) {
                        mMovie = Movie.decodeStream(mResources.openRawResource(mResId));
                        mTimeStart = 0;

                        gifLoaded();
                    }
                } else if (mGifType == GIF_TYPE_IS) {
                    if (mIs != null) {
                        mMovie = Movie.decodeStream(mIs);
                        mTimeStart = 0;

                        gifLoaded();
                    }
                } else Log.e(TAG, "gif load failed with mGifType:" + mGifType);
            }
        });
    }

    private void gifLoaded() {
        mHandler.post(() -> {
            if (mListener != null) {
                mListener.onGifLoaded(this);
                invalidateSelf();
            }
        });
    }

    @Override
    public void draw(@NonNull Canvas canvas) {
        if (mMovie == null) return;
//        Log.d(TAG, "draw() called with: canvas = [" + canvas + "]");
        updateTimeCurrent();

        float sx = 1f * getBounds().width() / mMovie.width();
        float sy = 1f * getBounds().height() / mMovie.height();
        Log.d(TAG, "draw() called with: sx = [" + sx + "]sy = [" + sy + "]");
        canvas.save();
        //scale the gif draw to fill bound of this.
        canvas.scale(sx, sy);
        mMovie.setTime((int) mTimeCurrent);
        mMovie.draw(canvas, 0, 0);
        canvas.restore();

        if (isVisible())
            invalidateSelf();
    }

    private void updateTimeCurrent() {
        if (mTimeStart == 0) mTimeStart = SystemClock.uptimeMillis();
        int movieDuration = mMovie.duration();
        if (movieDuration <= 0) movieDuration = DEFAULT_MOVIE_DURATION;
        mTimeCurrent = (SystemClock.uptimeMillis() - mTimeStart) % movieDuration;
    }

    @Override
    public void setAlpha(int alpha) {

    }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {

    }

    @Override
    public int getOpacity() {
        return PixelFormat.OPAQUE;
    }

    public Listener getListener() {
        return mListener;
    }

    public void setListener(Listener mListener) {
        this.mListener = mListener;
    }

    public interface Listener {
        @UiThread
        void onGifLoaded(Drawable drawable);
    }
}

使用demo

ImageView iv = findViewById(R.id.iv);
iv.setImageDrawable(new GifDrawable(getResources(),R.drawable.f3234));

后面发现glide自带gif显示功能,功能更强大方便,所以还是推荐大家用glide显示gif吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值