package com.owen.tvrecyclerview.example.tablayout; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Interpolator; /** * A 'fake' ValueAnimator implementation which uses a Runnable. */ class ValueAnimatorCompatImplEclairMr1 extends ValueAnimatorCompat.Impl { private static final int HANDLER_DELAY = 10; private static final int DEFAULT_DURATION = 200; private static final Handler sHandler = new Handler(Looper.getMainLooper()); private long mStartTime; private boolean mIsRunning; private final int[] mIntValues = new int[2]; private final float[] mFloatValues = new float[2]; private long mDuration = DEFAULT_DURATION; private Interpolator mInterpolator; private ValueAnimatorCompat.Impl.AnimatorListenerProxy mListener; private ValueAnimatorCompat.Impl.AnimatorUpdateListenerProxy mUpdateListener; private float mAnimatedFraction; private long mStartDelay = 0; @Override public void start() { if (mIsRunning) { // If we're already running, ignore return; } if (mInterpolator == null) { mInterpolator = new AccelerateDecelerateInterpolator(); } mStartTime = SystemClock.uptimeMillis(); mIsRunning = true; // Reset the animated fraction mAnimatedFraction = 0f; if (mListener != null) { mListener.onAnimationStart(); } sHandler.postDelayed(mRunnable, HANDLER_DELAY + mStartDelay); } @Override public boolean isRunning() { return mIsRunning; } @Override public void setInterpolator(Interpolator interpolator) { mInterpolator = interpolator; } @Override public void setListener(ValueAnimatorCompat.Impl.AnimatorListenerProxy listener) { mListener = listener; } @Override public void setUpdateListener(ValueAnimatorCompat.Impl.AnimatorUpdateListenerProxy updateListener) { mUpdateListener = updateListener; } @Override public void setIntValues(int from, int to) { mIntValues[0] = from; mIntValues[1] = to; } @Override public int getAnimatedIntValue() { return AnimationUtils.lerp(mIntValues[0], mIntValues[1], getAnimatedFraction()); } @Override public void setFloatValues(float from, float to) { mFloatValues[0] = from; mFloatValues[1] = to; } @Override public float getAnimatedFloatValue() { return AnimationUtils.lerp(mFloatValues[0], mFloatValues[1], getAnimatedFraction()); } @Override public void setDuration(long duration) { mDuration = duration; } @Override public void cancel() { mIsRunning = false; sHandler.removeCallbacks(mRunnable); if (mListener != null) { mListener.onAnimationCancel(); mListener.onAnimationEnd(); } } @Override public float getAnimatedFraction() { return mAnimatedFraction; } @Override public void end() { if (mIsRunning) { mIsRunning = false; sHandler.removeCallbacks(mRunnable); // Set our animated fraction to 1 mAnimatedFraction = 1f; if (mUpdateListener != null) { mUpdateListener.onAnimationUpdate(); } if (mListener != null) { mListener.onAnimationEnd(); } } } @Override public long getDuration() { return mDuration; } @Override void setStartDelay(long startDelay) { this.mStartDelay = startDelay; } private void update() { if (mIsRunning) { // Update the animated fraction final long elapsed = SystemClock.uptimeMillis() - mStartTime; final float linearFraction = MathUtils.constrain(elapsed / (float) mDuration, 0f, 1f); mAnimatedFraction = mInterpolator != null ? mInterpolator.getInterpolation(linearFraction) : linearFraction; // If we're running, dispatch tp the listener if (mUpdateListener != null) { mUpdateListener.onAnimationUpdate(); } // Check to see if we've passed the animation duration if (SystemClock.uptimeMillis() >= (mStartTime + mDuration)) { mIsRunning = false; if (mListener != null) { mListener.onAnimationEnd(); } } } if (mIsRunning) { // If we're still running, post another delayed runnable sHandler.postDelayed(mRunnable, HANDLER_DELAY); } } private final Runnable mRunnable = new Runnable() { public void run() { update(); } }; }