Android GIF 播放解决方案

题外话

先推荐一个安卓动画解决方案,如果公司的设计师可以使用AE设计APP内需求的动画效果(配合bodymovin插件导出含有动画内容的json文件),开发者就可以使用lottie框架实现复杂酷炫的动画效果。此方案兼顾了移动端Android和IOS双平台以及React Native,接入方便且播放效果好,故极力推荐。

Android GIF 播放解决方案_第1张图片
Adobe After Effects CC 2017.png

Lottie

Bodymovin

接下来进入正题了

在公司项目的开发中遇到了控制gif播放,计算gif播放次数,监听播放完成等使用场景。首先想到的是开发项目中已经引入的图片加载框架Glide附带的gif播放功能。

Glide

github地址

  • 首先在项目的build.gradle文件中声明Glide版本
   ...
    ext.glide_version = '3.8.0'
    ...
    repositories {
        google()
        jcenter()
    }
    dependencies {
        ...
    }
}```

-  在app中的build.gradle中引入Glide

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
...
compile "com.github.bumptech.glide:glide:$glide_version" //Glide
...
}


- 简单使用Glide播放GIF动画

Glide.with(ctx).load(R.drawable.cat).asGif()
.diskCacheStrategy(DiskCacheStrategy.SOURCE).into(gif_view)


- 在Kotlin中使用Glide控制播放GIF

Glide.with(ctx).load(R.drawable.cat_1).asGif()
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.listener(object : RequestListener {
override fun onException(e: Exception?, model: Int?,
target: Target?,
isFirstResource: Boolean): Boolean {
return false
}

                override fun onResourceReady(resource: GifDrawable?, 
                                             model: Int?,
                                             target: Target?,
                                             isFromMemoryCache: Boolean,
                                             isFirstResource: Boolean): Boolean {
                    Observable.just(resource).flatMap(Function> {
                        val decoder = it.decoder
                        val frameCount = it.frameCount
                        //计算GIF时长
                        val duration = (1..frameCount)
                                .map { decoder.getDelay(it).toLong() }
                                .sum()
                        return@Function Observable.just(it)
                                .delay(duration * loopCount,
                                TimeUnit.MILLISECONDS).repeat(1)
                    }).subscribeOn(Schedulers.io())
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe({
                                //播放完成进行后续操作
                                it.stop()
                                toast("Play Over")
                            })
                    return false
                }
            }).into(gif_view)
Glide个人感觉是当前最流行的图片加载框架,首推使用,不过我在公司项目的开发中发现加固后可能会出现GIF掉帧的情况,暂未解决。


###Fresco

[中文文档](https://www.fresco-cn.org) 
[github地址](https://github.com/facebook/fresco)

- 首先在项目的build.gradle文件中声明Fresco版本

```buildscript {
   ...
    ext.fresco_version = '1.3.0'
    ...
    repositories {
        google()
        jcenter()
    }
    dependencies {
        ...
    }
}```

-  在app中的build.gradle中引入Fresco

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
...
//fresco
compile "com.facebook.fresco:fresco:$fresco_version"
compile "com.facebook.fresco:animated-base-support:$fresco_version"//支持API14以下
compile "com.facebook.fresco:animated-gif:$fresco_version"//支持本地GIF
compile "com.facebook.fresco:animated-webp:$fresco_version"//支持网络GIF
...
}


- 使用Fresco播放GIF

 val controller = Fresco.newDraweeControllerBuilder()
            .setUri(Uri.parse("res:///" + R.drawable.cat_2))
            .setAutoPlayAnimations(true)
            .setControllerListener(object : BaseControllerListener() {
                override fun onFinalImageSet(id: String?,
                                           imageInfo: ImageInfo?,
                                           animatable: Animatable?) {
                    Observable.just(animatable).flatMap(Function> {
                        var duration: Long = 0
                        if (animatable is AbstractAnimatedDrawable) {
                            duration = animatable.duration.toLong()
                            animatable.start()
                        }
                        return@Function Observable.just("Play Over")
                                .delay(duration * loopCount,
                                TimeUnit.MILLISECONDS).repeat(1)
                    }).subscribeOn(Schedulers.io())
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe({
                                //播放完成进行后续操作
                                toast(it)
                                animatable?.stop()
                            })
                }
            }).build()
    gif_view.controller = controller

我在实际使用Fresco开发的时候感觉是比Glide的效果要好的,但是由于Fresco必须在布局中使用SimpleDraweeView,导致项目在替换图片加载框架时会很困难,同时Fresco的体积相对其他框架也更大,故需谨慎使用。

###android-gif-drawable
[github地址](https://github.com/koral--/android-gif-drawable/)

- 首先在项目的build.gradle文件中声明android-gif-drawable版本

```buildscript {
   ...
    ext.gif_drawable_version = '1.2.7'
    ...
    repositories {
        google()
        jcenter()
    }
    dependencies {
        ...
    }
}```

-  在app中的build.gradle中引入android-gif-drawable

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
...
compile "pl.droidsonroids.gif:android-gif-drawable:$gif_drawable_version"
...
}


- 使用android-gif-drawable播放GIF

val gifDrawable: GifDrawable = GifDrawable(resources, R.drawable.cat)
gifDrawable.loopCount = loop
gifDrawable.addAnimationListener {
if (it >= loop - 1) {
//播放完成后续操作
toast("Play Over")
}
}
gif_view.setImageDrawable(gifDrawable)


这个框架是gif播放中效果最好,最流畅的加载框架,但是由于目前版本仅支持本地gif文件的播放,如需要加载网络GIF图片以及缓存则需要自己拓展功能。


如有疑问可留言互相探讨学习。
附上Demo的github地址:
[GifPlayMaster](https://github.com/qlfabc/GifPlayMaster)

你可能感兴趣的:(Android GIF 播放解决方案)