• Android 实现GIF播放的几种方式


    1. Glide播放

    Glide是Android上比较常见的图片加载框架,其介绍可以看Android Glide简单使用

    布局文件,GIF文件可以在ImageView里面显示

    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ImageView
            android:id="@+id/iv_gif"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitCenter"/>
    
    RelativeLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    调用load()方法,导入图片并用ImageView显示

    var ivGif: ImageView = findViewById(R.id.iv_gif)
    Glide.with(this)
        .load("file:///android_asset/sample.gif")
        .into(ivGif)
    
    • 1
    • 2
    • 3
    • 4

    当然这样的方式只能循环播放,如果想要指定循环次数,需要调用GifDrawablesetLoopCount()方法。

    Glide.with(this)
        .asGif()
        .load("file:///android_asset/sample.gif")
        .into(object : SimpleTarget<GifDrawable>() {
            override fun onResourceReady(
                    resource: GifDrawable,
                    transition: Transition<in GifDrawable>?) {
                // 循环播放两次
                resource.setLoopCount(2)
                ivGif.setImageDrawable(resource)
    
                resource.start()
            }
    
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2. android-gif-drawable

    android-gif-drawable也是Android上比较常用的图片加载框架,android-gif-drawable 地址

    导入android-gif-drawable

    dependencies {
        implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.25'
    }
    
    • 1
    • 2
    • 3

    布局文件,GifImageView显示GIF文件

    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <pl.droidsonroids.gif.GifImageView
            android:id="@+id/iv_gif"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitCenter"/>
    
    RelativeLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    GifDrawable被用来加载图片资源,

    public GifDrawable(@NonNull Resources res, @RawRes @DrawableRes int id)
    public GifDrawable(@NonNull AssetManager assets, @NonNull String assetName)
    public GifDrawable(@NonNull String filePath)
    public GifDrawable(@NonNull File file)
    public GifDrawable(@NonNull InputStream stream)
    public GifDrawable(@NonNull AssetFileDescriptor afd)
    public GifDrawable(@NonNull FileDescriptor fd)
    public GifDrawable(@NonNull byte[] bytes)
    public GifDrawable(@NonNull ByteBuffer buffer)
    
    // 设置循环次数
    public void setLoopCount(@IntRange(from = 0, to = Character.MAX_VALUE) final int loopCount)
    // 设置播放速度
    public void setSpeed(@FloatRange(from = 0, fromInclusive = false) final float factor)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    播放GIF文件

    var ivGif: GifImageView = findViewById(R.id.iv_gif)
    var drawable = GifDrawable(assets, "sample.gif")
    ivGif.setImageDrawable(drawable)
    
    • 1
    • 2
    • 3

    3. Movie

    Movie是Android自带的类,可以用来加载播放GIF动画

    自定义GifImageView用来播放GIF文件

    class GifImageView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) :
        View(context, attrs, defStyleAttr) {
    
        private var mMovie: Movie? = null
        private var mMovieStart: Long = 0
        private var mStarted: Boolean = false
        private var mDuration: Int = 0
        private var mPaint: Paint = Paint()
    
        init {
            // 关闭硬件加速
            setLayerType(View.LAYER_TYPE_SOFTWARE, mPaint)
        }
    
        constructor(context: Context): this(context, null)
    
        constructor(context: Context, attrs: AttributeSet?): this(context, attrs, 0)
    
        // 设置播放资源,Movie支持decodeStream和decodeFile
        fun setResource(inputStream: InputStream) {
            try {
                mMovie = Movie.decodeStream(inputStream)
                mDuration = mMovie?.duration() ?: 1000
            } catch (e: Exception) {
            }
        }
    
        fun start() {
            mMovieStart = SystemClock.elapsedRealtime()
            mStarted = true
    
            invalidate()
        }
    
        fun stop() {
            mMovieStart = 0
            mStarted = false
            invalidate()
        }
    
        override fun onDraw(canvas: Canvas?) {
            var movie = mMovie
            if (mStarted && movie != null) {
                // 循环播放
                var realTime = (SystemClock.elapsedRealtime()  - mMovieStart).toInt() % mDuration
                movie.setTime(realTime)
    
                // 居中播放
                var scale = movie.width() * 1.0f / width
                movie.draw(canvas, 0f,  (height - movie.height() * scale) / 2)
    
                invalidate()
            }
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    布局文件

    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.blog.demo.image.gif.GifImageView
            android:id="@+id/iv_gif"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    RelativeLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    播放GIF文件,文中的GifImageView只是实现了循环播放的功能,可以自行定义其他功能。

    var ivGif: GifImageView = findViewById(R.id.iv_gif)
    ivGif.setResource(assets.open("sample.gif"))
    
    ivGif.start()
    
    • 1
    • 2
    • 3
    • 4

    4. AnimatedImageDrawable

    AnimatedImageDrawable是Android9.0引入的绘制和显示GIF和WebP等动图的类,而ImageDecoder同样是Android9.0新引入的图像解码器。

    var ivGif: ImageView = findViewById(R.id.iv_gif)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        val source = ImageDecoder.createSource(assets, "sample.gif")
        Thread {
            val drawable = ImageDecoder.decodeDrawable(source)
            ivGif.post {
                ivGif.setImageDrawable(drawable)
                if (drawable is AnimatedImageDrawable) {
                    drawable.start()
                }
            }
        }.start()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    5. 总结

    这4种方式都能很好地在手机上运行,但在小米盒子上出现了不同的问题。

    • Glide本身就是很好用的图片框架,但在小米盒子上出现了运行缓慢的问题,一个3秒的GIF图片需要十几秒的时间才能跑完。
    • android-gif-drawable没有出现运行缓慢的问题,但刷新闪烁比较严重。
    • Movie能正常显示GIF图片,但如果想只运行一次的情况下,很难显示到最后一帧的图片。
    • AnimatedImageDrawable最大的问题是版本要求太高,需要Android9.0。
  • 相关阅读:
    魔兽世界安装插件后进游戏闪退的一个原因。
    <图像处理> Harris角点检测
    RedisTemplate使用详解
    使用vscode进行简单的多文件编译
    Pinpoint--基础--03--安装部署
    JDK JRE JVM区别
    Synchronized 与 Lock 的使用
    统一网关 Gateway(黑马程序员)
    Docker数据卷篇
    二叉树基础
  • 原文地址:https://blog.csdn.net/chennai1101/article/details/127733528