diff --git a/library/build.gradle b/library/build.gradle index 4ae5650792..e2fa09bd16 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -13,6 +13,7 @@ dependencies { api project(':third_party:disklrucache') api project(':annotation') api "com.android.support:support-fragment:${ANDROID_SUPPORT_VERSION}" + api "com.android.support:animated-vector-drawable:${ANDROID_SUPPORT_VERSION}" compileOnly "com.android.support:appcompat-v7:${ANDROID_SUPPORT_VERSION}" if (project.plugins.hasPlugin('net.ltgt.errorprone')) { diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawable.java b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawable.java index cd0aa52483..a17577b953 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawable.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawable.java @@ -14,6 +14,7 @@ import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; +import android.support.graphics.drawable.Animatable2Compat; import android.view.Gravity; import com.bumptech.glide.Glide; import com.bumptech.glide.gifdecoder.GifDecoder; @@ -21,12 +22,14 @@ import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.util.Preconditions; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; /** * An animated {@link android.graphics.drawable.Drawable} that plays the frames of an animated GIF. */ public class GifDrawable extends Drawable implements GifFrameLoader.FrameCallback, - Animatable { + Animatable, Animatable2Compat { /** * A constant indicating that an animated drawable should loop continuously. */ @@ -76,6 +79,11 @@ public class GifDrawable extends Drawable implements GifFrameLoader.FrameCallbac private Paint paint; private Rect destRect; + /** + * Callbacks to notify loop completion of a gif, where the loop count is explicitly specified. + */ + private List animationCallbacks; + /** * Constructor for GifDrawable. * @@ -351,10 +359,19 @@ public void onFrameReady() { } if (maxLoopCount != LOOP_FOREVER && loopCount >= maxLoopCount) { + notifyAnimationEndToListeners(); stop(); } } + private void notifyAnimationEndToListeners() { + if (animationCallbacks != null) { + for (int i = 0, size = animationCallbacks.size(); i < size; i++) { + animationCallbacks.get(i).onAnimationEnd(this); + } + } + } + @Override public ConstantState getConstantState() { return state; @@ -390,6 +407,50 @@ public void setLoopCount(int loopCount) { } } + /** + * Register callback to listen to GifDrawable animation end event after specific loop count + * set by {@link GifDrawable#setLoopCount(int)} + * + * Note: Unregister this in onLoadCleared to avoid potential memory leak. + * @see GifDrawable#unregisterAnimationCallback(AnimationCallback). + * + * @param animationCallback Animation callback {@link Animatable2Compat.AnimationCallback}. + */ + @Override + public void registerAnimationCallback(@NonNull AnimationCallback animationCallback) { + if (animationCallback == null) { + return; + } + if (animationCallbacks == null) { + animationCallbacks = new ArrayList<>(); + } + animationCallbacks.add(animationCallback); + } + + /** + * Unregister animation callback. + * + * @param animationCallback Animation callback {@link Animatable2Compat.AnimationCallback}. + * @return true when the animation callback is successfully removed, otherwise false. + */ + @Override + public boolean unregisterAnimationCallback(@NonNull AnimationCallback animationCallback) { + if (animationCallbacks == null || animationCallback == null) { + return false; + } + return animationCallbacks.remove(animationCallback); + } + + /** + * Clears out all the animation callbacks. + */ + @Override + public void clearAnimationCallbacks() { + if (animationCallbacks != null) { + animationCallbacks.clear(); + } + } + static final class GifState extends ConstantState { @VisibleForTesting final GifFrameLoader frameLoader;