背景
gif图片的特殊性
安卓里常用的图片有jpg,png,webp,gif.前三者都是位图模式,而gif实际上是几张图片依次播放的动画.
安卓原生并不支持gif的显示.
Fresco图片加载框架能够显示gif动画,但是有几个坑.
fresco 显示gif的基本方法:开启自动播放就可以了
PipelineDraweeController controller =
(PipelineDraweeController) Fresco.newDraweeControllerBuilder()
.setImageRequest(request)
.setControllerListener(listener)
.setOldController(draweeView.getController())
.setAutoPlayAnimations(true) //自动播放gif动画
.build();
draweeView.setController(controller);
//或者,不显式地构建imagerequest:
public static void setSupportGif(SimpleDraweeView draweeView,String url){
PipelineDraweeController controller =(PipelineDraweeController) Fresco.newDraweeControllerBuilder()
.setUri(url)
.setOldController(draweeView.getController())
.setAutoPlayAnimations(true) //自动播放gif动画
.build();
draweeView.setController(controller);
}
gif圆角和圆形:圆角与动画不可兼得
fresco里设置圆角可使用以下两种方式:
- 默认使用一个 shader绘制圆角,但是仅仅占位图和所要显示的图有圆角效果。失败示意图和重下载示意图无圆角效果,且这种圆角方式不支持动画。
- 叠加一个solid color来绘制圆角。但是背景需要固定成指定的颜色。 在XML中指定 roundWithOverlayColor,或者通过调用setOverlayColor来完成此设定。很多时候,xml里设置没有效果,要代码中进行设定.
很显然,gif动画要显示圆角,是要通过第二种方式,盖一层圆角颜色,其实颜色下方,图像还是长方形的。圆角状态下,动画是不会动的,即使开启了自动播放.
通过BaseBitmapDataSubscriber获取bitmap时,如果图像是gif,那么虽然回调是success,但返回的bitmap为null。那么,如何让gif格式时返回的bitmap为第一帧的图像?
解决的思路是:
在成功的回调里,去拿到已经缓存的gif文件,对其进行解码,然后拿到第一帧的bitmap。
如果对bitmap大小有要求,那么可以在解码时就指定生成的图片大小,获取拿到第一帧后再压缩。两者对比肯定第二种省内存。
当然,最好是服务器能直接将gif转换成jpg返回。
/**
* 拿到指定宽高,并经过Processor处理的bitmap
* @param url
* @param context
* @param width
* @param height
* @param processor 后处理器,可为null
* @param listener
*
*/
public static void getBitmapWithProcessor(@NonNull final String url,@NonNull Context context,@NonNull final int width,@NonNull final int height,
@Nullable BasePostprocessor processor,@NonNull final BitmapListener listener){
ResizeOptions resizeOptions = null;
if (width !=0 && height != 0 ){
resizeOptions = new ResizeOptions(width, height);
}
ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
.setProgressiveRenderingEnabled(false) //我们是拿bitmap对象,不是显示,所以这里不需要渐进渲染
.setPostprocessor(processor)
.setResizeOptions(resizeOptions)//无法支持gif
.build();
ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, context);
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
protected void onNewResultImpl(Bitmap bitmap) {
//注意,gif图片解码方法与普通图片不一样,是无法拿到bitmap的。如果要把gif的第一帧的bitmap返回,怎么做?
//GifImage.create(bytes).decode(1l,9).getFrameInfo(1).
if (bitmap == null ){
File cacheFile = getFileFromDiskCache(url);
//还要判断文件是不是gif格式的
if ("gif".equalsIgnoreCase(getRealType(cacheFile))){//通过读取文件头的方式来判断
Bitmap bitmapGif = GifUtils.getBitmapFromGifFile(cacheFile);//拿到gif第一帧的bitmap
Bitmap target = MyBitmapUtils.compressBitmap(bitmapGif, true, width, height);//将bitmap压缩到指定宽高。
if (target != null) {
listener.onSuccess(target);
} else {
listener.onFail();
}
}else {
listener.onFail();
}
}else {
listener.onSuccess(bitmap);
}
}
@Override
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
listener.onFail();
}
}, CallerThreadExecutor.getInstance());
}
gif解析的算法有待优化,可参考:
加载超大gif图,fresco也会及其卡顿甚至OOM:
服务器将gif图缩小后传输给客户端。比如七牛的图片处理api能够做到对gif图片的缩小尺寸以及按规定尺寸裁剪。或者干脆转成jpg。
http://developer.qiniu.com/code/v6/api/kodo-api/image/imagemogr2.html
/thumbnail/<imageSizeGeometry>
/crop/<imageSizeAndOffsetGeometry>