package com.kaichunlin.transition.animation; import android.os.Handler; import android.support.annotation.IntDef; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.UiThread; import com.kaichunlin.transition.TransitionOperation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.HashSet; import java.util.Set; /** */ @UiThread public abstract class AbstractAnimation implements Animation { @IntDef({CONTROLLER_ANIMATION, CONTROLLER_ANIMATOR}) @Retention(RetentionPolicy.SOURCE) public @interface StateControllerType { } public static final int CONTROLLER_ANIMATION = 0; public static final int CONTROLLER_ANIMATOR = 1; protected final Runnable mStartAnimation = new Runnable() { @Override public void run() { startAnimation(); } }; protected Handler mHandler; private final Set<AnimationListener> mAnimationListenerSet = new HashSet<>(); private int mDuration = -1; private boolean mReverse; private boolean mAnimating; private final TransitionOperation mTransition; private @StateControllerType int mStateControllerType = CONTROLLER_ANIMATION; public AbstractAnimation() { mTransition = null; } public AbstractAnimation(@NonNull TransitionOperation transition) { mTransition = transition; } /** * The driver for the animation, can be either {@link #CONTROLLER_ANIMATION} or * {@link #CONTROLLER_ANIMATOR}, currently the chief difference is that {@link #CONTROLLER_ANIMATION} * may be more performant in some situations, where as {@link #CONTROLLER_ANIMATOR} allows * pausing/resuming the animation on API level 19 or later. * <p> * {@link #CONTROLLER_ANIMATION} is the default, unless a valid View cannot be found (for example when animating * the menu), then {@link #CONTROLLER_ANIMATOR} is automatically used. */ public void setStateControllerType(@StateControllerType int stateControllerType) { mStateControllerType = stateControllerType; } @StateControllerType public int getStateControllerType() { return mStateControllerType; } protected TransitionOperation getTransition() { return mTransition; } /** * @param listener */ public void addAnimationListener(AnimationListener listener) { mAnimationListenerSet.add(listener); } /** * @param listener */ public void removeAnimationListener(AnimationListener listener) { mAnimationListenerSet.remove(listener); } public void setDuration(@IntRange(from = 0) int duration) { mDuration = duration; } public int getDuration() { return mDuration; } public void setReverseAnimation(boolean reverse) { mReverse = reverse; } /** * @return */ public boolean isReverseAnimation() { return mReverse; } /** * Starts the animation with the default duration. */ public abstract void startAnimation(); /** * Starts the animation with the specified duration in milliseconds. * * @param duration */ public abstract void startAnimation(@IntRange(from = 0) int duration); /** * Starts the animation with the default duration (300 ms) after a set delay. * * @param delay time to delay the animation in milliseconds */ @Override public void startAnimationDelayed(@IntRange(from = 0) int delay) { if (mHandler == null) { mHandler = new Handler(); } mHandler.postDelayed(mStartAnimation, delay); } public void startAnimationDelayed(@IntRange(from = 0) final int duration, @IntRange(from = 0) int delay) { if (mHandler == null) { mHandler = new Handler(); } mHandler.postDelayed(new Runnable() { @Override public void run() { startAnimation(duration); } }, delay); } protected void setAnimating(boolean animating) { mAnimating = animating; } public boolean isAnimating() { return mAnimating; } protected void notifyAnimationStart() { if (mAnimationListenerSet.size() == 0) { return; } for (AnimationListener listener : mAnimationListenerSet) { listener.onAnimationStart(this); } } protected void notifyAnimationEnd() { if (mAnimationListenerSet.size() == 0) { return; } for (AnimationListener listener : mAnimationListenerSet) { listener.onAnimationEnd(this); } } protected void notifyAnimationCancel() { if (mAnimationListenerSet.size() == 0) { return; } for (AnimationListener listener : mAnimationListenerSet) { listener.onAnimationCancel(this); } } protected void notifyAnimationReset() { if (mAnimationListenerSet.size() == 0) { return; } for (AnimationListener listener : mAnimationListenerSet) { listener.onAnimationReset(this); } } }