//对外通知动画开始/结束/取消/重复执行事件的监听器列表ArrayList
//开始动画执行,如果动画有开始延迟(startDelay),则动画在延迟之后开始运行(running),动画初始值在第一帧开始设置,随后调用onAnimationStart//调用此方法后,当前动画就在调用线程上运行,线程需要一个Looper,如果动画引起View变化,则应在UI线程调用start,或在UI线程处理onAnimationUpdatepublic void start();//取消动画运行,与end不同的是,cancel让动画直接结束,并使状态立刻复位,而end让动画执行到最后一帧,再使状态复位。调用cancel,外部会先收到onAnimationCancel,再收到onAnimationEnd,也就是收到两个回调。此方法应该在运行动画的线程上调用,否则操作并无作用(动画是依附在运行线程的ThreadLocal中的,以此来避开多线程操作)。public void cancel();//结束动画运行,动画会先执行到最后一帧,然后再调用onAnimationEnd,而cancel事件不会有执行到最后一帧的动作。此方法也只能在动画运行线程执行。public void end();//暂停一个正在运行的动画,只能在动画运行的线程上调用。如果动画还没start(isStarted=false)或者已经结束,此调用会被忽略,被暂停的动画可以通过resume()来恢复。//置mPaused为true,并对外通知onAnimationPause事件。public void pause();//恢复一个暂停的动画,动画从暂停处继续运行。只能在动画运行的线程上调用。如果当前动画不是paused状态,则此调用忽略。//置mPaused为false,对外通知onAnimationResume事件。public void resume();//动画当前是否处于暂停状态。public boolean isPaused();//获取动画的开始延迟,也就是动画从start到running的延迟时间,单位毫秒。public abstract long getStartDelay();//设置动画开始延迟public abstract void setStartDelay(long startDelay);//设置动画执行一次的耗时,单位mspublic abstract Animator setDuration(long duration);//获取动画执行一次的耗时。public abstract long getDuration();//设置动画的时间插值器,也就是动画的变化速率,默认是AccelerateDecelerateInterpolatorpublic abstract void setInterpolator(TimeInterpolator value);//获取动画的时间插值器public TimeInterpolator getInterpolator();//返回动画是否正在执行,正在执行状态是动画start并且过了startDelay的时间后,到动画结束之前的状态。public abstract boolean isRunning();//返回动画是否已经开始。从动画调用start后到动画结束之前都返回true,比isRunning涵盖的时间要广,多出的就是startDelay的时间。在startDelay内,isRunning返回false,isStarted返回true。public boolean isStarted();//添加一个AnimatorListener监听(监听start/repeat/end/cancel)public void addListener(AnimatorListener listener);//移除一个已经设置的AnimatorListenerpublic void removeListener(AnimatorListener listener);//获取已经设置的AnimatorListener的集合。public ArrayList
public static ValueAnimator ofInt(int... values) {ValueAnimator anim = new ValueAnimator();anim.setIntValues(values);return anim;
}
public static ValueAnimator ofArgb(int... values) {ValueAnimator anim = new ValueAnimator();anim.setIntValues(values);anim.setEvaluator(ArgbEvaluator.getInstance());return anim;
}
public static ValueAnimator ofFloat(float... values);
public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) {ValueAnimator anim = new ValueAnimator();anim.setValues(values);return anim;
}
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {ValueAnimator anim = new ValueAnimator();anim.setObjectValues(values);anim.setEvaluator(evaluator);return anim;
}
public static void setDurationScale(float durationScale) {sDurationScale = durationScale;
}public static float getDurationScale() {return sDurationScale;
}
void initAnimation() {if (!mInitialized) {int numValues = mValues. length;for (int i = 0; i
public void setCurrentPlayTime(long playTime) {float fraction = mUnscaledDuration > 0 ? (float) playTime / mUnscaledDuration : 1;setCurrentFraction(fraction);
}
//设置动画当前的执行位置(执行位置与执行时间线性一一对应)
//fraction值是基于动画时长的0~1取值,超出1的考虑动画循环执行情况取模
public void setCurrentFraction(float fraction) {initAnimation();//此方法可能是第一帧&#xff0c;此处要考虑初始化动画if (fraction <0) {//fraction保证>&#61;0fraction &#61; 0 ;}int iteration &#61; (int) fraction; //当前执行动画的轮数if (fraction &#61;&#61; 1) {//动画刚刚走完一轮&#xff0c;到最后一帧&#xff0c;此时动画的轮数应为1&#xff0c;表现为mCurrentIteration应等于0iteration -&#61; 1 ;} else if (fraction > 1) {//动画还没执行完所有轮数if (iteration <(mRepeatCount &#43; 1) || mRepeatCount &#61;&#61; INFINITE ) {if (mRepeatMode &#61;&#61; REVERSE) {//动画reverse时&#xff0c;奇数轮动画从结束帧向开始帧执行mPlayingBackwards &#61; (iteration % 2) !&#61; 0 ;}//去掉重复执行&#xff0c;动画真实的位置fraction &#61; fraction % 1f;//在这种情况下&#xff0c;动画应该完全已经执行了iteration轮&#xff0c;此时正在iteration&#43;1轮内执行&#xff0c;此处不用-1} else {//动画已到达最后一帧&#xff0c;轮数iteration要-1fraction &#61; 1;iteration -&#61; 1;}} else {//还在第一轮执行&#xff0c;第一轮本应是顺序执行&#xff0c;但如果当前动画被调用了reverse&#xff0c;则此处是逆序执行mPlayingBackwards &#61; mReversing;}//mCurrentIteration动画执行轮数需要与mRepeatCount对比&#xff0c;mRepeatCount从0开始&#xff0c;所以mCurrentIteration也从0开始mCurrentIteration &#61; iteration;//重新计算动画开始时间&#xff0c;也就是当前时间往前倒推&#xff0c;这样后面执行时动画开始时间就改变了&#xff0c;动画可以接着向下执行long seekTime &#61; (long) ( mDuration * fraction);long currentTime &#61; AnimationUtils.currentAnimationTimeMillis();mStartTime &#61; currentTime - seekTime;mStartTimeCommitted &#61; true; // do not allow start time to be compensated for jank//当前动画不再执行状态&#xff0c;记录标志位if (mPlayingState !&#61; RUNNING) {mSeekFraction &#61; fraction;mPlayingState &#61; SEEKED;}//如果动画正在逆序从结束帧到初始帧执行&#xff0c;则调整归一化的fractionif (mPlayingBackwards) {fraction &#61; 1f - fraction;}//动画运行到当前时间指定的帧&#xff0c;见3.3.6animateValue(fraction);
}
//playBackwards值true表示动画逆序执行&#xff0c;false表示顺序执行
private void start(boolean playBackwards) {if (Looper.myLooper() &#61;&#61; null) {//属性动画是支持非主线程调用的&#xff0c;但前提是线程有Looperthrow new AndroidRuntimeException("Animators may only be run on Looper threads");}//记录标志位mReversing &#61; playBackwards;mPlayingBackwards &#61; playBackwards;if (playBackwards && mSeekFraction !&#61; - 1) {//逆序执行且曾经有过seek动作(先setCurrentFraction再start)if (mSeekFraction &#61;&#61; 0 && mCurrentIteration &#61;&#61; 0 ) {// special case: reversing from seek-to-0 should act as if not seeked at all//如果seek到动画初始位置&#xff0c;则新的seek位置还保持在0mSeekFraction &#61; 0;} else if (mRepeatCount &#61;&#61; INFINITE) {//无限重复时新的seek位置&#xff0c;reverse模式下&#xff0c;fraction保持在0&#xff5e;1之间即可mSeekFraction &#61; 1 - (mSeekFraction % 1);} else {//有限循环时&#xff0c;新位置为总的Fraction&#xff08;1 &#43; mRepeatCount&#xff09;减去当前已经执行到的位置&#xff08;mCurrentIteration &#43; mSeekFraction&#xff09;mSeekFraction &#61; 1 &#43; mRepeatCount - (mCurrentIteration &#43; mSeekFraction);}//以上三个分支涵盖了如果seek到某个位置&#xff0c;而动画逆序执行时&#xff0c;动画应当执行到的位置//假设动画逆序执行&#xff0c;则seek到0.8的位置&#xff0c;其实是从0.2执行到0.mCurrentIteration &#61; (int) mSeekFraction;mSeekFraction &#61; mSeekFraction % 1;}if (mCurrentIteration > 0 && mRepeatMode &#61;&#61; REVERSE &&(mCurrentIteration <(mRepeatCount &#43; 1) || mRepeatCount &#61;&#61; INFINITE)) {// if we were seeked to some other iteration in a reversing animator,// figure out the correct direction to start playing based on the iteration//reverse模式下&#xff0c;如果当前动画已经执行过超过1轮&#xff0c;而且动画还需要继续执行&#xff0c;则重新计算动画方向if (playBackwards) {//逆序执行模式下&#xff0c;奇数轮执行方向是顺序的(mPlayingBackwards&#61;false)&#xff0c;偶数轮执行方向是逆序的mPlayingBackwards &#61; (mCurrentIteration % 2 ) &#61;&#61; 0 ;} else {//顺序执行模式下&#xff0c;奇数轮执行的方向是逆序的&#xff0c;比如轮数0顺序执行&#xff0c;轮数1逆序执行(mPlayingBackwards&#61;true )mPlayingBackwards &#61; (mCurrentIteration % 2 ) !&#61; 0 ;}}int prevPlayingState &#61; mPlayingState;//STOPPED动画还没开始运行, RUNNING正在运行, SEEKED动画快进到了某个位置mPlayingState &#61; STOPPED;mStarted &#61; true;//动画已开始mStartedDelay &#61; false;//动画还没开始经历StartedDelay阶段mPaused &#61; false ;//动画不属于暂停状态updateScaledDuration(); // in case the scale factor has changed since creation time//在当前线程的ThreadLocal内获取/建立AnimationHandler对象AnimationHandler animationHandler &#61; getOrCreateAnimationHandler();//在当前线程对应的AnimationHandler中增加当前动画的引用animationHandler.mPendingAnimations .add(this);if (mStartDelay &#61;&#61; 0) {// This sets the initial value of the animation, prior to actually starting it runningif (prevPlayingState !&#61; SEEKED) {//动画没有startDelay时&#xff0c;外部也没有seek动作&#xff0c;这时动画立刻开始运行&#xff0c;从时间0开始setCurrentPlayTime(0);}//动画此时状态还保持STOPPED&#xff0c;在动画开始第一帧时状态改为RUNNINGmPlayingState &#61; STOPPED;//没有开始延迟的动画在start后就处于running状态mRunning &#61; true;//通知外部动画开始notifyStartListeners();}//开始动画插值计算&#xff08;AnimationHandler在指定时间触发属性值插值计算&#xff09;animationHandler.start();
}
public void cancel() {// Only cancel if the animation is actually running or has been started and is about// to run//仅当动画start后才能cancelAnimationHandler handler &#61; getOrCreateAnimationHandler();//获取AnimationHandlerif (mPlayingState !&#61; STOPPED|| handler.mPendingAnimations .contains(this)|| handler.mDelayedAnims .contains(this)) {//动画当前动画正在运行// Only notify listeners if the animator has actually startedif ((mStarted || mRunning) && mListeners !&#61; null) {if (!mRunning) {// If it&#39;s not yet running, then start listeners weren&#39;t called. Call them now.//当前动画在start之后&#xff0c;第一帧之前&#xff0c;通知外部动画开始&#xff0c;notifyStartListeners();}//通知外部动画取消动作ArrayList
}
protected void endAnimation(AnimationHandler handler) {//从当前线程的AnimationHandler移除当前的动画handler.mAnimations.remove(this);handler.mPendingAnimations .remove(this);handler.mDelayedAnims .remove(this);//动画结束的标志位mPlayingState &#61; STOPPED;mPaused &#61; false ;if ((mStarted || mRunning) && mListeners !&#61; null ) {//动画已开始if (!mRunning) {// If it&#39;s not yet running, then start listeners weren&#39;t called. Call them now.//考虑动画开始但未运行的情况notifyStartListeners();}//通知动画结束&#xff0c;从代码可以看到&#xff0c;外部cancel的调用会引起onAnimationCancel和onAnimationEnd的回调ArrayList
public void end() {//获取当前线程的AnimationHandlerAnimationHandler handler &#61; getOrCreateAnimationHandler();if (!handler.mAnimations.contains( this) && !handler.mPendingAnimations .contains(this)) {// Special case if the animation has not yet started; get it ready for ending//如果动画还没schedule到handler内&#xff0c;则动画还没开始运行&#xff0c;此时开始执行动画&#xff0c;为后面的结束动画做准备//标识一个带startDelay的动画是否开始经历延迟阶段&#xff0c;这里动画都快要结束了&#xff0c;这里就置false了mStartedDelay &#61; false;startAnimation(handler);//动画还没开始&#xff0c;我们启动动画&#xff0c;随后再结束动画&#xff0c;见下面的代码mStarted &#61; true;} else if (!mInitialized) {initAnimation();//动画还没初始化&#xff0c;我们初始化它}//让动画执行到最后一帧&#xff0c;见3.3.6animateValue(mPlayingBackwards ? 0f : 1f );//结束动画&#xff0c;具体见上面的代码endAnimation(handler);
}
private void startAnimation(AnimationHandler handler) {initAnimation();//如果动画没初始化&#xff0c;初始化动画handler.mAnimations .add(this);//把动画添加到AnimationHandlerif (mStartDelay > 0 && mListeners !&#61; null) {// Listeners were already notified in start() if startDelay is 0; this is// just for delayed animations//startDelay为0则start时已经调用过onAnimationStart&#xff0c;只有>0才需要在此处调用notifyStartListeners();}
}
public void reverse() {//动画方向逆转mPlayingBackwards &#61; !mPlayingBackwards;if (mPlayingState &#61;&#61; RUNNING) {//动画正在运行long currentTime &#61; AnimationUtils.currentAnimationTimeMillis();long currentPlayTime &#61; currentTime - mStartTime;long timeLeft &#61; mDuration - currentPlayTime;//因为方向逆转&#xff0c;动画开始事件mStartTime调整为另一个方向的开始时间&#xff0c;认为动画已经执行了timeLeft&#xff0c;剩余currPlayTime需要执行mStartTime &#61; currentTime - timeLeft;mStartTimeCommitted &#61; true; // do not allow start time to be compensated for jank//修改reverse的标志位mReversing &#61; !mReversing;} else if (mStarted) {//动画start了但未运行&#xff0c;则当前处于startDelay内&#xff0c;reverse的最终状态就是当前的状态&#xff0c;所以直接结束动画//注意此处所有的状态的复位了&#xff0c;mReversing &#61; falseend();} else {//动画不在start&#xff0c;也没running&#xff0c;此时reverse直接从当前位置逆序执行动画start(true);}
}
public static interface AnimatorUpdateListener {/**动画开始进行新一帧的刷新时的回调*/void onAnimationUpdate(ValueAnimator animation);
}
protected static class AnimationHandler {// 单个进程内所有活跃的属性动画的列表&#xff0c;每个线程只持有一个AnimationHandler(ThreadLocal机制)protected final ArrayList
/*** 对当前正处于startDelay阶段动画的进行处理&#xff0c;返回值表示动画是否需要被唤醒并被放入待执行队列。** &#64;param currentTime 当前动画时间&#xff0c;用于判断当前动画是否已经超出了startDelay* &#64;return 返回true表示动画已经超出了startDelay&#xff0c;应被放入待执行队列。*/
private boolean delayedAnimationFrame(long currentTime) {if (!mStartedDelay) {//尚未执行动画延迟&#xff0c;则开始进入执行动画延迟状态&#xff0c;记录开始进入动画延迟的开始时间mStartedDelay &#61; true;mDelayStartTime &#61; currentTime;}if (mPaused) {if (mPauseTime <0) {mPauseTime &#61; currentTime;//记录暂停时间}//动画被暂停了&#xff0c;则不能加入活跃动画列表return false;} else if (mResumed) {mResumed &#61; false;//消费了resume事件if (mPauseTime > 0) {// 重新计算动画延迟的开始时间&#xff0c;去掉暂停到恢复中间的时间mDelayStartTime &#43;&#61; (currentTime - mPauseTime);}}//计算动画在startDelay阶段真正经历的时间long deltaTime &#61; currentTime - mDelayStartTime;if (deltaTime > mStartDelay) {// 动画已经超出了延迟时间&#xff0c;可以移入活跃队列真正执行了mStartTime &#61; mDelayStartTime &#43; mStartDelay;mStartTimeCommitted &#61; true;mPlayingState &#61; RUNNING;return true;}//动画还在startDelay时间段内return false;
}
/**对动画开始时间增加adjustment作为动画第一次执行与动画开始绘制之间的补偿。*/
void commitAnimationFrame(long adjustment) {if (!mStartTimeCommitted) {mStartTimeCommitted &#61; true;if (mPlayingState &#61;&#61; RUNNING && adjustment > 0) {mStartTime &#43;&#61; adjustment;}}
}
/*** 处理动画的某一帧&#xff0c;可能需要调整startTime&#xff0c;返回true表示动画需要结束了*/
final boolean doAnimationFrame(long frameTime) {if (mPlayingState &#61;&#61; STOPPED) {//当前动画状态是STOPPEDmPlayingState &#61; RUNNING;if (mSeekFraction <0) {//没有调用seekTomStartTime &#61; frameTime;} else {//如果调用了seekTo&#xff0c;则重新计算StartTime来应用seek的时间long seekTime &#61; (long) (mDuration * mSeekFraction);mStartTime &#61; frameTime - seekTime;mSeekFraction &#61; -1;}mStartTimeCommitted &#61; false; // 支持动画开始与动画绘制的差距补偿}if (mPaused) {//动画已经pause了则不处理if (mPauseTime <0) {mPauseTime &#61; frameTime;}return false;} else if (mResumed) {mResumed &#61; false;if (mPauseTime > 0) {// 重新计算startTime&#xff0c;去掉pause到resume的间隔mStartTime &#43;&#61; (frameTime - mPauseTime);mStartTimeCommitted &#61; false; // 支持动画开始与动画绘制的差距补偿}}// frameTime可能位于startTime之前&#xff0c;这种情况很少见&#xff0c;只有往回seek才可能发生final long currentTime &#61; Math.max(frameTime, mStartTime);return animationFrame(currentTime);//见3.3.5
}
/**根据当前时间计算新一帧的属性插值。currentTime参数是由Handler发出的时序脉冲&#xff0c;指出当前动画已经执行的时间。返回true表示动画需要结束了。*/
boolean animationFrame(long currentTime) {boolean done &#61; false;switch (mPlayingState) {case RUNNING:case SEEKED://计算新的动画执行耗时&#xff08;归一化&#xff0c;但可能大于1&#xff09;float fraction &#61; mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;if (mDuration &#61;&#61; 0 && mRepeatCount !&#61; INFINITE) {// Skip to the endmCurrentIteration &#61; mRepeatCount;if (!mReversing) {mPlayingBackwards &#61; false;}}if (fraction >&#61; 1f) {if (mCurrentIteration
/*** 此方法在每次动画帧刷新时都会调用&#xff0c;通过将动画已执行的时间&#xff08;归一化后的时间&#xff09;转化为插值时间&#xff0c;再通过Evaluator计算属性插值。* 在Animation帧刷新时和end()时方法都会被调用。** &#64;param fraction 动画已经执行的时间*/
&#64;CallSuper
void animateValue(float fraction) {//计算速率变化插值后的动画时间fraction &#61; mInterpolator.getInterpolation(fraction);//保存当前时间mCurrentFraction &#61; fraction;int numValues &#61; mValues.length;for (int i &#61; 0; i