package com.bumptech.glide.request.transition;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import com.bumptech.glide.load.DataSource;
/**
* A factory class that produces a new {@link Transition} that varies depending on whether or not
* the drawable was loaded from the memory cache and whether or not the drawable is the first image
* to be put on the target.
*
* <p> Resources are usually loaded from the memory cache just before the user can see the view, for
* example when the user changes screens or scrolls back and forth in a list. In those cases the
* user typically does not expect to see a transition. As a result, when the resource is loaded from
* the memory cache this factory produces an {@link NoTransition}.
*/
public class DrawableCrossFadeFactory implements TransitionFactory<Drawable> {
private final ViewAnimationFactory<Drawable> viewAnimationFactory;
private final int duration;
private final boolean isCrossFadeEnabled;
private DrawableCrossFadeTransition firstResourceTransition;
private DrawableCrossFadeTransition secondResourceTransition;
protected DrawableCrossFadeFactory(ViewAnimationFactory<Drawable> viewAnimationFactory,
int duration, boolean isCrossFadeEnabled) {
this.viewAnimationFactory = viewAnimationFactory;
this.duration = duration;
this.isCrossFadeEnabled = isCrossFadeEnabled;
}
@Override
public Transition<Drawable> build(DataSource dataSource, boolean isFirstResource) {
if (dataSource == DataSource.MEMORY_CACHE) {
return NoTransition.get();
} else if (isFirstResource) {
return getFirstResourceTransition(dataSource);
} else {
return getSecondResourceTransition(dataSource);
}
}
private Transition<Drawable> getFirstResourceTransition(DataSource dataSource) {
if (firstResourceTransition == null) {
firstResourceTransition = buildTransition(dataSource, true /*isFirstResource*/);
}
return firstResourceTransition;
}
private Transition<Drawable> getSecondResourceTransition(DataSource dataSource) {
if (secondResourceTransition == null) {
secondResourceTransition = buildTransition(dataSource, false /*isFirstResource*/);
}
return secondResourceTransition;
}
private DrawableCrossFadeTransition buildTransition(DataSource dataSource,
boolean isFirstResource) {
Transition<Drawable> defaultAnimation =
viewAnimationFactory.build(dataSource, isFirstResource);
return new DrawableCrossFadeTransition(defaultAnimation, duration, isCrossFadeEnabled);
}
private static final class DefaultViewTransitionAnimationFactory implements
ViewTransition.ViewTransitionAnimationFactory {
private final int durationMillis;
DefaultViewTransitionAnimationFactory(int durationMillis) {
this.durationMillis = durationMillis;
}
@Override
public Animation build(Context context) {
AlphaAnimation animation = new AlphaAnimation(0f, 1f);
animation.setDuration(durationMillis);
return animation;
}
}
/**
* A Builder for {@link DrawableCrossFadeFactory}.
*/
public static class Builder {
private static final int DEFAULT_DURATION_MS = 300;
private int durationMillis;
private ViewAnimationFactory<Drawable> factory;
private boolean isCrossFadeEnabled;
public Builder() {
this(DEFAULT_DURATION_MS);
}
/**
* @param durationMillis The duration of both the default animation when no previous Drawable
* is present and the cross fade animation when a previous Drawable is present. This value
* will not be used by the default animation if {@link #setDefaultAnimationId(int)},
* {@link #setDefaultAnimation(Animation)}, or
* {@link #setDefaultAnimationFactory(ViewAnimationFactory)} is called.
*/
public Builder(int durationMillis) {
this.durationMillis = durationMillis;
factory = new ViewAnimationFactory<>(
new DefaultViewTransitionAnimationFactory(durationMillis));
}
/**
* Enables or disables animating the alpha of the {@link Drawable} the cross fade will animate
* from.
*
* <p>Defaults to {@code false}.
*
* @param isCrossFadeEnabled If {@code true} the previous {@link Drawable}'s alpha will be
* animated from 100 to 0 while the new {@link Drawable}'s alpha is
* animated from 0 to 100. Otherwise the previous {@link Drawable}'s
* alpha will remain at 100 throughout the animation. See
* {@link android.graphics.drawable.TransitionDrawable#setCrossFadeEnabled(boolean)}
*/
public Builder setCrossFadeEnabled(boolean isCrossFadeEnabled) {
this.isCrossFadeEnabled = isCrossFadeEnabled;
return this;
}
/**
* Sets the resource id of the {@link Animation} to use when no previous {@link Drawable} is
* available to animate from.
*
* <p>Defaults to a simple fade in.
*/
public Builder setDefaultAnimationId(int animationId) {
return setDefaultAnimationFactory(new ViewAnimationFactory<Drawable>(animationId));
}
/**
* Sets the {@link Animation} to use when no previous {@link Drawable} is available to animate
* from.
*
* <p>It is not safe to use the same {@link Animation} object for multiple animations
* simultaneously. Always pass in a new instance to this method.
*/
public Builder setDefaultAnimation(Animation animation) {
return setDefaultAnimationFactory(new ViewAnimationFactory<Drawable>(animation));
}
/**
* Sets the {@link ViewAnimationFactory} to use to generate animations to animate when no
* previous {@link Drawable} is available to animate from.
*/
public Builder setDefaultAnimationFactory(ViewAnimationFactory<Drawable> factory) {
this.factory = factory;
return this;
}
public DrawableCrossFadeFactory build() {
return new DrawableCrossFadeFactory(factory, durationMillis, isCrossFadeEnabled);
}
}
}