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