在图片选择器中提到gif文件是使用了普通的ImageView来实现的,如果需要实现gif图片的缩放那么就需要自定义SSIV。
首先需要GIF解码器,可以选择使用glide的gif decoder,也可以使用原版的https://gist.github.com/devunwired/4479231。
改造SSIV主要修改的地方是setImage方法,最后是使用了BitmapLoadTask加载图片文件,改为使用自定义的GifBitmapLoadTask进行加载,加载完成后先显示第一帧图片,如果帧数为1那么应该是静态图,不再进行下面的操作,如果不为1,则开启线程读取下一帧的图片并显示,然后一直循环读取并显示。
初始化decorder并开始加载
public final void setImage(@NonNull ImageSource imageSource, ImageSource previewSource, ImageViewState state) {
…………
if (mDecoder == null) {
mDecoder = new GifDecoder();
}
//mDecoder.setDefaultBitmapConfig(Bitmap.Config.RGB_565);
// Load gif bitmap
GifImageLoadTask task = new GifImageLoadTask(this, getContext(), uri, false, mDecoder);
execute(task);
}
GifImageLoadTask代码和BitmapImageLoadTask类似,不过这里是加载第一帧图片
private static class GifImageLoadTask extends AsyncTask<Void, Void, Integer> {
private final WeakReference<GifSubsamplingScaleImageView> viewRef;
private final Uri uri;
private final boolean preview;
private final GifDecoder gifDecoder;
private Bitmap bitmap;
private Exception exception;
public GifImageLoadTask(GifSubsamplingScaleImageView gifSubsamplingScaleImageView, Context context, Uri uri, boolean preview, GifDecoder gifDecoder) {
this.viewRef = new WeakReference<>(gifSubsamplingScaleImageView);
this.uri = uri;
this.preview = preview;
this.gifDecoder = gifDecoder;
}
@Override
public Integer doInBackground(Void... voidArr) {
InputStream inputStream = null;
try {
try {
if (uri.getPath() != null) inputStream = new FileInputStream(uri.getPath());
} catch (FileNotFoundException e) {
exception = e;
}
if (inputStream == null) {
return null;
}
gifDecoder.read(inputStream, inputStream.available());
gifDecoder.advance();
bitmap = gifDecoder.getNextFrame();
if (bitmap != null) {
return 0;
} else {
exception = new FileNotFoundException();
return null;
}
} catch (Exception ex) {
this.exception = ex;
} catch (OutOfMemoryError error) {
this.exception = new RuntimeException(error);
}
return null;
}
@Override
public void onPostExecute(Integer num) {
GifSubsamplingScaleImageView view = viewRef.get();
if (view == null) {
return;
}
if (num != null) {
if (preview) {
view.onPreviewLoaded(bitmap);
} else {
view.onImageLoaded(bitmap, num, false);
}
} else if (exception != null && view.onImageEventListener != null) {
if (preview) {
view.onImageEventListener.onPreviewLoadError(exception);
} else {
view.onImageEventListener.onImageLoadError(exception);
}
}
}
}
加载完成后再进行下一步的判断
public synchronized void onImageLoaded(Bitmap bitmap, int sOrientation, boolean bitmapIsCached) {
debug("onImageLoaded");
// If actual dimensions don't match the declared size, reset everything.
if (this.sWidth > 0 && this.sHeight > 0 && (this.sWidth != bitmap.getWidth() || this.sHeight != bitmap.getHeight())) {
reset(false);
}
if (this.bitmap != null && !this.bitmapIsCached) {
this.bitmap.recycle();
}
if (this.bitmap != null && this.bitmapIsCached && onImageEventListener != null) {
onImageEventListener.onPreviewReleased();
}
this.bitmapIsCached = bitmapIsCached;
this.sOrientation = sOrientation;
loadImage(bitmap, true);
if (mDecoder != null && mDecoder.getFrameCount() > 1) {
this.drawThread = new DrawThread();
this.drawThread.start();
}
}
开启DrawThread进行循环的读取下一帧图片。
public class DrawThread extends Thread {
public DrawThread() {
}
public void run() {
if (mDecoder != null) {
mIsRun = true;
while (mIsRun) {
if (!waitIfPaused() && mDecoder != null) {
long startTime = SystemClock.elapsedRealtime();
mDecoder.advance();
Bitmap bitmap = mDecoder.getNextFrame();
if (bitmap != null) {
if (checkReady() || checkImageLoaded()) {
Message msg = Message.obtain();
msg.obj = bitmap;
msg.what = 0;
mHandler.sendMessage(msg);
}
long f = ((long) mDecoder.getNextDelay()) - (SystemClock.elapsedRealtime() - startTime);
if (f <= 0 ) {
f = 0;
}
SystemClock.sleep(f);
}
} else {
return;
}
}
mDecoder.release();
mDecoder = null;
}
}
}
这样基本实现了gif图片的显示和缩放,源码地址。