生活随笔
收集整理的這篇文章主要介紹了
Android - Animation(二)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Android - Animation(一)?一文總結(jié)了 Android中的補(bǔ)間動(dòng)畫 ( View?Animation/ Tween Animation)和 幀動(dòng)畫 ( Drawable?Animation/ Frame Animation)的使用
本篇文章主要解析 屬性動(dòng)畫( Property Animation, android3.0引入 )的實(shí)現(xiàn)原理
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 下篇 ? 屬性動(dòng)畫的實(shí)現(xiàn)原理
先來看屬性動(dòng)畫的最簡單實(shí)現(xiàn):
第一種方式:先在?/res/animator/文件夾下創(chuàng)建translate.xml文件定義動(dòng)畫。再在Java文件里引用并開啟 [java] ?view plaincopy
?? <? xml?version="1.0" ?encoding= "utf-8" ?
>????
<objectAnimator????? ????xmlns:android="http://schemas.android.com/apk/res/android" ????? ????android:propertyName="translationX" ?? ?? ????android:duration="2000" ?? ?? ????android:valueFrom="0.0" ?? ?? ????android:valueTo="20.0" >?? ?? </objectAnimator>?? ?? ?? mButton1?=?(Button)?findViewById(R.id.button1);?? mButton1.setOnClickListener(this );?? ?? mObjectAnimator?=?AnimatorInflater.loadAnimator(this ,?R.animator.translate);?? mObjectAnimator.setTarget(mButton1);?? public ? void ?onClick(View?v)?{?? ????switch (v.getId()){?? ????case ?R.id.button1:?? ????????mObjectAnimator.start();???? ????????break ;???? ????}?? }?? 另外一種方式:直接在Java文件里創(chuàng)建并使用動(dòng)畫 [java] ?view plaincopy
mButton1?=?(Button)?findViewById(R.id.button1);?? mButton1.setOnClickListener(this );?? public ? void ?onClick(View?v)?{?? ?????? ????ObjectAnimator.ofFloat(mButton1,?"translationX" ,? 0 .0f, 20 .0f).setDuration( 3000 ).start();?? }??
簡單地說,屬性動(dòng)畫就是在指定的時(shí)間內(nèi)改變對(duì)象的屬性值。
上述的樣例。從代碼上看,設(shè)置了動(dòng)畫運(yùn)行的時(shí)間、作用的目標(biāo)對(duì)象 mButton1及其屬性translationX以及屬性值的初始值和終于值,但從效果上看, mButton1在2秒鐘之內(nèi)在屏幕上勻速的移動(dòng)了一段距離。于是我們能夠猜想:
在start()方法運(yùn)行之后。是不是會(huì)不斷地計(jì)算出一個(gè)值并賦給目標(biāo)對(duì)象的屬性? 在屬性動(dòng)畫中。是不是也有和補(bǔ)間動(dòng)畫里類似的插值器來改變動(dòng)畫的運(yùn)行速率? 假設(shè)有這種一個(gè)插值器的話,須要賦給目標(biāo)對(duì)象的屬性的那個(gè)值的計(jì)算是不是也和這個(gè)插值器有關(guān)? ... ...
帶著這些猜想,我們就以?在Java文件里創(chuàng)建動(dòng)畫的方式? 為例來梳理屬性動(dòng)畫的實(shí)現(xiàn)原理。
首先是ObjectAnimator類的靜態(tài)方法ofFloat /* Constructs and returns an ObjectAnimator that animates between float values. A single value implies that that value is the one being animated to. Two values imply a starting and ending values. More than two values imply a starting value, values to animate through along the way, and an ending value (these values will be distributed evenly across the duration of the animation).
創(chuàng)建并返回 一個(gè)基于float?類型數(shù)值的ObjectAnimator?對(duì)象,一個(gè)value值代表動(dòng)畫的終點(diǎn),兩個(gè)value?值,則一個(gè)是起點(diǎn), 還有一個(gè)是終點(diǎn),假設(shè)是多個(gè)值, 則中間的值代表動(dòng)畫將要經(jīng)過的點(diǎn)?,而且這些點(diǎn)會(huì)均勻地分布在動(dòng)畫的運(yùn)行過程中 */ public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
? ? ? ? ObjectAnimator anim = new ObjectAnimator (target, propertyName); ? ? ? ? ? ?? anim.setFloatValues(values); ?? ? ? ? return anim; }
ObjectAnimator的構(gòu)造函數(shù): [java] ?view plaincopy
private ?ObjectAnimator(Object?target,?String?propertyName)?{?? ?????? ?????? ????mTarget?=?target;?? ????setPropertyName(propertyName);?? }?? setPropertyName方法: [java] ?view plaincopy
public ? void ?setPropertyName(String?propertyName)?{?? ?????? ?????? ?????? ?????? ????if ?(mValues?!=? null )?{?? ????????PropertyValuesHolder?valuesHolder?=?mValues[0 ];?? ????????String?oldName?=?valuesHolder.getPropertyName();?? ????????valuesHolder.setPropertyName(propertyName);?? ????????mValuesMap.remove(oldName);?? ????????mValuesMap.put(propertyName,?valuesHolder);?? ????}?? ?????? ????mPropertyName?=?propertyName;?? ?????? ?????? ?????? ?????? ???? 默認(rèn)值為false
?? ????mInitialized?=?false ;?? }?? 所以。 第一次運(yùn)行ObjectAnimator anim = new ObjectAnimator(target, propertyName);僅僅做了兩件事情: 1、為ObjectAnimator?的成員變量mTarget和mPropertyName賦值 2、將mInitialized(定義在ObjectAnimator?的父類?ValueAnimator 中)的值設(shè)為false 接下來是上文中? 處的anim.setFloatValues(values)方法: @Override public void setFloatValues(float... values) { if (mValues == null || mValues.length == 0) {
? //第一次運(yùn)行mValues == null // No values yet - this animator is being constructed piecemeal. Init the values with?whatever the current propertyName is ? ? ? ??//?mValues眼下尚未賦值——當(dāng)前的animator?正在構(gòu)建中,將通過傳入的values初始化mValues if (mProperty != null) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? //mProperty?為ObjectAnimator的成員變量?private Property mProperty,第一次運(yùn)行時(shí)也為null ? ? ? ? ? ? ? ? ? ? ? ? ? ? setValues( PropertyValuesHolder.ofFloat (mProperty, values)); } else {
? ? ?? ? ? ? ? ? ? ? ? ? ? // 第一次運(yùn)行時(shí)。下列函數(shù)將被調(diào)用: ? setValues(PropertyValuesHolder.ofFloat(mPropertyName, values)); } } else { super.setFloatValues(values); } }
在分析 setValues()方法之前先來看Pro pertyValuesHolder的ofFloat()方法:
/** * Constructs and returns a PropertyValuesHolder with a given property name and?set of float values. */
?// 通過給定的propertyName 和 values創(chuàng)建并返回一個(gè)PropertyValuesHolder?對(duì)象 public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
? ?? ? ? ? ? return new FloatPropertyValuesHolder(propertyName, values); }
接著FloatPropertyValuesHolder的構(gòu)造函數(shù):
public FloatPropertyValuesHolder(String propertyName, float... values) { super(propertyName);
? ? ? ? ? ? ? setFloatValues(values); }
首先運(yùn)行的是FloatPropertyValuesHolder 的父類 PropertyValuesHolder的構(gòu)造函數(shù):
[java] ?view plaincopy
private ?PropertyValuesHolder(String?propertyName)?{?? ?????? ????mPropertyName?=?propertyName;?? }??
我們注意到,FloatPropertyValuesHolder?、IntPropertyValuesHolder都是PropertyValuesHolder的靜態(tài)內(nèi)部類 來看一下PropertyValuesHolder的類定義: [java] ?view plaincopy
? ? ? ? ?? ???? ???? public ? class ?PropertyValuesHolder? implements ?Cloneable?{?}?? 接下來是上文中 ? 處setFloatValues()方法:
@Override public void setFloatValues(float... values) { ? ? ? ?? ? ?? ? ? super.setFloatValues(values); ? ? ? ? ? ? mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet; } 首先運(yùn)行的又是父類的方法:
public void setFloatValues(float... values) { ? ? ? ? // 為成員變量 Class? mValueType(定義在父類 PropertyValuesHolder中 )賦值 ? ? ? ? mValueType = float.class; ? ? ? ? ? ? ? mKeyframeSet = KeyframeSet.ofFloat(values); }
然后,mKeyframeSet = KeyframeSet.ofFloat(values),先來看KeyframeSet類的定義:
[java] ?view plaincopy
? ? ? ? ?? ??? ??? class ?KeyframeSet?{?}??
對(duì)KeyframeSet有一個(gè)大概了解之后。再來看一下Keyframe類的定義:
[java] ?view plaincopy
? ? ? ? ? ?? ??? public ? abstract ? class ?Keyframe? implements ?Cloneable?{?}?? 來看上文中 ? 處的KeyframeSet的ofFloat(values)方法:
public static KeyframeSet ofFloat(float... values) { ? ? ? ? boolean badValue = false;//初始化一個(gè)標(biāo)示。 之后 用于標(biāo)示 values[i]是不是一個(gè)數(shù)字 ? ? ? ? int numKeyframes = values.length;//獲取傳入的參數(shù)的個(gè)數(shù) ? ? ? ? //初始化一個(gè) FloatKeyframe ?類型的數(shù)組,數(shù)組的長度為 numKeyframes和2之間的較大者,這個(gè)比較easy理解 ? ? ? ??FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)]; ? ? ? ? if (numKeyframes == 1) { ? ?? ???//假設(shè)我們僅僅傳入了一個(gè)參數(shù),那么這個(gè)參數(shù)將用于構(gòu)建 keyframes[1]。 keyframes[0]的值則由 ofFloat(0f)來構(gòu)建。例如以下: ? ? ? ? ? ? ??keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f); // Constructs a Keyframe object with the given time. The value at this time will be derived ?from the target object when the animation first starts ... ... // 使用給定的time構(gòu)造一個(gè)Keyframe?對(duì)象。在動(dòng)畫第一次運(yùn)行時(shí)。這個(gè)給定的時(shí)間相應(yīng)的value將利用動(dòng)畫的目標(biāo)對(duì)象去獲得 ... ... public static Keyframe ofFloat(float fraction) { ? ? ? ? // FloatKeyframe和IntKeyframe都是 Keyframe ?的靜態(tài)內(nèi)部類。這個(gè)和 PropertyValuesHolder結(jié)構(gòu)是類似的 ? ? ? ? return new FloatKeyframe(fraction); FloatKeyframe(float fraction) { ?// 為成員變量float mFraction(定義在 Keyframe ?中 )賦值, ?注意,在此時(shí)。成員變量mValue的值還沒有設(shè)置 ? mFraction = fraction; ?//? 為成員變量 Class mValueType (定義在 Keyframe ?中 )賦值 ?mValueType = float.class; } } ? ? ? ? ? ? ? ? ? ? ??keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]); /** ? ?* Constructs a Keyframe object with the given time and value. The time defines the time, as a proportion of an overall? ? ?* animation's duration, at which the value will hold true for the animation ... ... ? //? 使用給定的time和value構(gòu)造一個(gè) Keyframe ?對(duì)象,time作為整個(gè)動(dòng)畫運(yùn)行過程中的一個(gè)時(shí)間比例。是一個(gè)0到1之間的值 ... ...? public static Keyframe ofFloat(float fraction, float value) { ? ? ? ? return new FloatKeyframe(fraction, value); FloatKeyframe(float fraction, float value) { ? ? ? ? ? ? mFraction = fraction; ? ? ? ? ? ? mValue = value; ? ? ? ? ? ? mValueType = float.class; ? ? ? ? ? ? mHasValue = true; } } ? ? ? ? ? if (Float.isNaN(values[0])) { ? ? ? ? ? ? ? ? ? badValue = true;?// 假設(shè)傳入的值不是一個(gè)數(shù)值,將標(biāo)示badValue改為true ? ? ? ? ? ?} //從以上分析能夠看到。當(dāng)我們僅僅傳入一個(gè)值時(shí),將用1 (代表時(shí)間終點(diǎn)) 和這個(gè)值構(gòu)建出動(dòng)畫運(yùn)行的最后一幀的 Keyframe // ?對(duì)象。 而動(dòng)畫的第一幀相應(yīng)的 Keyframe ?對(duì)象,則默認(rèn)由0(代表時(shí)間的起點(diǎn))來構(gòu)建,這一幀相應(yīng)的值將在動(dòng)畫第一次 // 運(yùn)行時(shí)由動(dòng)畫 作用的對(duì)象來獲得,假設(shè)我們傳入的參數(shù)大于1個(gè),比方2個(gè)或者多個(gè)。則運(yùn)行下邊的邏輯: ? ? ? ? ? ?} else { //邏輯比較簡單,假設(shè)傳入的參數(shù)大于1,則,用 0f和values[0]構(gòu)建出動(dòng)畫的第一幀相應(yīng)的 Keyframe對(duì)象并賦值給 keyframes[0], //代表第一個(gè)value相應(yīng)動(dòng)畫的起始值 ? ? ? ? ? ? ? ? ?keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]); // 然后。進(jìn)行遍歷,利用 values[i] 和 其 所相應(yīng)的幀在整個(gè)動(dòng)畫運(yùn)行過程中應(yīng)該處于的時(shí)間比例—— ? //? (float) i / (numKeyframes - 1) ?來構(gòu)建每個(gè) Keyframe對(duì)象。一般我們傳入的參數(shù)是兩個(gè)。所以第二個(gè)參數(shù)就相應(yīng)了 // 動(dòng)畫運(yùn)行的最后一幀的屬性值。 事實(shí)上,在這里,屬性動(dòng)畫實(shí)現(xiàn)的原理已經(jīng)開始有所體現(xiàn)了。 ? ? ? ? ? ? ? ? ?for (int i = 1; i < numKeyframes; ++i) { ? ? ? ? ? ? ? ? ? ? ? ??keyframes[i] =? (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]); ? ? ? ? ? ? ? ? ? ? ? ? if (Float.isNaN(values[i])) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? badValue = true; // 同上,假設(shè)傳入的值不是一個(gè)數(shù)值,將標(biāo)示badValue改為true ? ? ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ?} ? ? ? ? ? } ? ? ? ? ? if (badValue) { ? ? ? ? ? ? ? ? ? Log.w("Animator", "Bad value (NaN) in float animator"); // 假設(shè)傳入的值不是一個(gè)數(shù)值,運(yùn)行此邏輯 ? ? ? ? ? ?} //以上邏輯主要就是創(chuàng)建 keyframes數(shù)組。該數(shù)組中放的是依據(jù)傳入的value值創(chuàng)建出來的動(dòng)畫運(yùn)行過程中的關(guān)鍵幀對(duì)象 //即 (主要是) 將一個(gè) mKeyframes ?成員變量完畢初始化的 FloatKeyframeSet對(duì)象返回 ? ? ? ? ??return new FloatKeyframeSet(keyframes); public FloatKeyframeSet(FloatKeyframe... keyframes) { ? ? ? ?? // 走的是父類的構(gòu)造函數(shù) ? ? ? ? super(keyframes); public KeyframeSet(Keyframe... keyframes) { ? ? ? ? //這個(gè)邏輯就比較簡單了 ? ? ? ? mNumKeyframes = keyframes.length;//為成員變量int mNumKeyframes()賦值 ? ? ? ? mKeyframes = new ArrayList<Keyframe>(); ? ? ? ? //將接收到的 keyframes數(shù)組中的元素加入到 成員變量ArrayList<Keyframe> mKeyframes集合中 ? ? ? ??mKeyframes.addAll(Arrays.asList(keyframes)); ? ? ? ? mFirstKeyframe = mKeyframes.get(0);// 初始化第一幀相應(yīng)的成員變量Keyframe mFirstKeyframe ? ? ? ? mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);? // 初始化最后一幀相應(yīng)的成員變量Keyframe? mLastKeyframe ? ? ? ?? // 初始化插值器相應(yīng)的成員變量TimeInterpolator mInterpolator,眼下為null ? ? ? ? mInterpolator = mLastKeyframe.getInterpolator(); private TimeInterpolator mInterpolator = null; public TimeInterpolator getInterpolator() { ? ? ? ? return mInterpolator; } } } }
至此,KeyframeSet的ofFloat(values)方法完畢了,基本的邏輯是:
依據(jù)傳入的value值創(chuàng)建出動(dòng)畫運(yùn)行過程中的關(guān)鍵幀對(duì)象,將這些對(duì)象放在一個(gè)數(shù)組中,new一個(gè)FloatKeyframeSet對(duì)象,然后將數(shù)組中的這些元素,放在FloatKeyframeSet對(duì)象的成員變量ArrayList<Keyframe> mKeyframes中,并將FloatKeyframeSet對(duì)象返回。 上邊第 ? 步將這個(gè)FloatKeyframeSet對(duì)象賦值給PropertyValuesHolder的成員變量KeyframeSet mKeyframeSet,于是。第 ? 步也運(yùn)行完了,接著。在setFloatValues()方法中。運(yùn)行完第? 步后: [java] ?view plaincopy
mFloatKeyframeSet?=?(FloatKeyframeSet)?mKeyframeSet;?? ?? ??
于是。第 ? 步也運(yùn)行完了,第 ? 步把完畢初始化的FloatPropertyValuesHolder對(duì)象返回,第 ? 步將利用第? 步返回的對(duì)象作為參數(shù)。運(yùn)行setValues()方法。 (該方法在ObjectAnimator的父類ValueAnimator類中定義),詳細(xì)邏輯例如以下:
[java] ?view plaincopy
public ? void ?setValues(PropertyValuesHolder...?values)?{?? ????int ?numValues?=?values.length;?? ?????? ????mValues?=?values;?? ?????? ?????? ?????? ?????? ?????? ?????? ????mValuesMap?=?new ?HashMap<String,?PropertyValuesHolder>(numValues);?? ????for ?( int ?i?=? 0 ;?i?<?numValues;?++i)?{?? ????????PropertyValuesHolder?valuesHolder?=?values[i];?? ????????mValuesMap.put(valuesHolder.getPropertyName(),?valuesHolder);?? ????}?? ?????? ????mInitialized?=?false ;?? }??
至此,用于創(chuàng)建屬性動(dòng)畫對(duì)象的ObjectAnimator類的靜態(tài)方法ofFloat的大體邏輯分析完畢了。 簡單總結(jié)一下:
ObjectAnimator.ofFloat(Object target, String propertyName, float... values)?創(chuàng)建了一個(gè)ObjectAnimator對(duì)象,而且: 1、將?target 賦給 ObjectAnimator 的成員變量? private Object mTarget 2、將? propertyName 賦給? ObjectAnimator 的成員變量 ?private String mPropertyName 3、創(chuàng)建一個(gè) FloatPropertyValuesHolder 對(duì)象 3.1、將? propertyName 賦給? FloatPropertyValuesHolder 的 成員變量? String mPropertyName(在 FloatPropertyValuesHolder ?的父類? PropertyValuesHolder中定義 ) 3.2、 將? float.class?賦給? FloatPropertyValuesHolder 的 成員變量?Class mValueType(在 FloatPropertyValuesHolder ?的父類? PropertyValuesHolder中定義 ) 3.3、創(chuàng)建一個(gè)? FloatKeyframeSet對(duì)象 3.3.1、創(chuàng)建一個(gè) FloatKeyframe 類型的數(shù)組 keyframes? 3.3.2、依據(jù)傳入的 values 構(gòu)造出? keyframes 數(shù)組中的每一項(xiàng)(關(guān)鍵幀對(duì)象 Keyframe ) 3.3.3、將 ? keyframes 數(shù)組中的每一項(xiàng)加入到 ? FloatKeyframeSet 對(duì)象的成員變量? ? ?ArrayList<Keyframe>mKeyframes(在 FloatKeyframeSet ?的父類 KeyframeSet中定義 )中 3.4、將? FloatKeyframeSet 對(duì)象 賦給? PropertyValuesHolder 的成員變量? KeyframeSet mKeyframeSet 3.5、將? mKeyframeSet 向下轉(zhuǎn)型為?FloatKeyframeSet 類型賦給? FloatPropertyValuesHolder 的成員變量? FloatKeyframeSet mFloatKeyframeSet 4、將? FloatPropertyValuesHolder 對(duì)象? 賦給 ObjectAnimator 的成員變量 ?PropertyValuesHolder[] mValues ? ?(在 ObjectAnimator ?的父類 ValueAnimator中定義 ) 5、利用已完畢初始化的 FloatPropertyValuesHolder ?對(duì)象及其 mPropertyName屬性。 ? ? ?完畢成員變量HashMap<String, PropertyValuesHolder> mValuesMap(在ValueAnimator中定義 )的 初始化 動(dòng)畫開始運(yùn)行之前。另一個(gè)關(guān)鍵的方法 —?setDuration(long) public ObjectAnimator setDuration(long duration) { // 運(yùn)行的是父類?ValueAnimator 的setDuration()方法 super.setDuration(duration); private static float sDurationScale = 1.0f; // How long the animation should last in ms 默認(rèn)時(shí)間是300毫秒 private long mDuration = (long)(300 * sDurationScale); private long mUnscaledDuration = 300; public ValueAnimator setDuration(long duration) { ? ? ? ? if (duration < 0) { ? ? ?? ? ???// 若傳入的值小于零,拋出異常 ? ? ? ? ? ? ? ?throw new IllegalArgumentException("Animators cannot have negative duration: " + ? ?duration); ? ? ? ? } ? ? ? ? mUnscaledDuration = duration; ? ? ? ? mDuration = (long)(duration * sDurationScale); ? ? ? ? return this; } ? ? ? ? return this; } 另外,在?setDuration( )方法中,我們能夠看到 成員變量 mDuration 的值終于是由我們調(diào)用?setDuration( )方法時(shí)傳入的?duration 乘以?sDurationScale 得出的,sDurationScale 默認(rèn)值為?1.0f ; 而且 ValueAnimator 類中提供了靜態(tài)方法 setDurationScale() 供我們使用 public static void setDurationScale(float durationScale) { ? ? ? ? sDurationScale = durationScale; } 我們能夠利用這種方法改變動(dòng)畫的速度 下邊來看屬性動(dòng)畫的運(yùn)行過程 —— start( )方法 從上文的分析,我們注意到,使用ObjectAnimator類的靜態(tài)方法ofFloat來創(chuàng)建動(dòng)畫對(duì)象的過程中,ObjectAnimator類僅僅是復(fù)寫了父類ValueAnimator的一部分方法,相同也僅僅擁有部分僅僅屬于自己的成員變量,其實(shí)。我們?cè)谑褂脤傩詣?dòng)畫時(shí)。所涉及到的類的繼承關(guān)系例如以下: [java] ?view plaincopy
? ? ? ?? ??? public ? abstract ? class ?Animator? implements ?Cloneable?{?}?? Animator 是屬性動(dòng)畫體系的超類,它定義了諸如?start()、cancel()、end()、setDuration(long duration)、setInterpolator(TimeInterpolator value)、isRunning()、addListener(AnimatorListener listener)、removeAllListeners() 等方法 AnimatorSet 在屬性動(dòng)畫中的使用方法和在補(bǔ)間動(dòng)畫中類似,不細(xì)講了 ValueAnimator 和?ObjectAnimator 是屬性動(dòng)畫的實(shí)現(xiàn)類,它們的差別在哪里?分析完start( ) 方法,再結(jié)合上邊的?ofFloat( ) 方法進(jìn)行總結(jié) ObjectAnimator 的?start() 方法: [java] ?view plaincopy
public ? void ?start()?{?? ?????? ????AnimationHandler?handler?=?sAnimationHandler.get();?? ????if ?(handler?!=? null )?{?...?...?}? ?? ????super .start();? ?? }?? ValueAnimator 的? start() 方法: public void start() { ? ? ? ? start(false); } /** ? ? ?* Start the animation playing. This version of start() takes a boolean flag that indicates? whether the animation should play in? ? ? ?*? reverse. ? The flag is usually false, but may be set? to true if called from the reverse() method. ? ? ?* <p>The animation started by calling this method will be run on the thread that called? this method. This thread should have ? ? ?*? a Looper on it (a runtime exception will be thrown if? this is not the case). Also, if the animation will animate? properties ?of ? ? ? ?* objects in the view hierarchy, then the calling thread should be the UI? thread for that view hierarchy.</p> ? ? ?*/ ? ? ?// 開始運(yùn)行動(dòng)畫,這個(gè) start() ?方法 有一個(gè)boolean型的參數(shù)用于標(biāo)示該動(dòng)畫是否須要反轉(zhuǎn),該參數(shù) 一般 為false。可是也可能 ? ? // 被設(shè)置為true假設(shè) start() ?方法是從 ? reverse() ?方法中調(diào)用的,該動(dòng)畫將執(zhí)行在調(diào)用? start() ?方法的線程里,這個(gè)線程須要擁有 ? ? ?//? 一個(gè) Looper 對(duì)象,否則會(huì)發(fā)生異常 ... ... private void start(boolean playBackwards) { if (Looper.myLooper() == null) { ? ? ? ? ? ? ? throw new AndroidRuntimeException("Animators may only be run on Looper threads"); ? ? ? ? } ? ? ? ? mPlayingBackwards = playBackwards;?// 動(dòng)畫是否反轉(zhuǎn)的標(biāo)示 //? This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the? ?repeatCount //??(if repeatCount!=INFINITE), the animation ends? 這個(gè)變量用于記錄當(dāng)前動(dòng)畫的循環(huán)次數(shù)。當(dāng) mCurrentIteration?超過了 //?repeatCount(假設(shè)repeatCount 不等于 -1),動(dòng)畫將被終止,該變量默認(rèn)值為0 ? ? ? ? mCurrentIteration = 0;? ? ? ? ? mPlayingState = STOPPED;//標(biāo)示動(dòng)畫的狀態(tài),下面是ValueAnimator中對(duì)動(dòng)畫狀態(tài)的定義: /** ? ? ?* Values used with internal variable mPlayingState to indicate the current state of an?animation. ? ? ?*/ ? ???// 變量mPlayingState?使用這些值來標(biāo)示動(dòng)畫的狀態(tài) ? ? static final int STOPPED ? ?= 0;?// Not yet playing 尚未開始 ? ? static final int RUNNING ? ?= 1;?// Playing normally 正常進(jìn)行中 ? ? static final int SEEKED ? ? = 2; // Seeked to some time value ? ? ? ? ? mStarted = true;? //?Tracks whether a startDelay'd animation has begun playing through the startDelay. ? ? ? ? mStartedDelay = false; //?Whether this animator is currently in a paused state. ? ? ? ? mPaused = false; ? ? ? ? AnimationHandler animationHandler = getOrCreateAnimationHandler(); private static AnimationHandler getOrCreateAnimationHandler() { ? ? ? ? AnimationHandler handler = sAnimationHandler.get(); ? ? ? ? if (handler == null) {// 第一次運(yùn)行,走下邊的邏輯 ? ? ? ? ? ? ? handler = new AnimationHandler(); ? ? ? ? ? ? ? sAnimationHandler.set(handler);// 此處涉及ThreadLocal的使用,暫不細(xì)說 ? ? ? ? } ? ? ? ? return handler; } // 將此動(dòng)畫對(duì)象加入到AnimationHandler的mPendingAnimations集合中 animationHandler.mPendingAnimations.add(this); ? ? ? ? if (mStartDelay == 0) { ? ?// The amount of time in ms to delay starting the animation after start() is called 調(diào)用start()方法之后延遲多少時(shí)間播放動(dòng)畫 ? ? private long mStartDelay = 0;// 默覺得零,運(yùn)行下邊的邏輯 ? ? ? ? ?? // This sets the initial value of the animation, prior to actually starting it running ? ? ? ? ? ???setCurrentPlayTime(0); ? ? ? ? ? ? ?mPlayingState = STOPPED; ? ? ? ? ? ? ?mRunning = true; ? ? ? ? ? ? ?notifyStartListeners(); ? ? ? ? } ? ? ? ??animationHandler.start(); } 在ValueAnimator的start( )方法中,須要重點(diǎn)分析的就是setCurrentPlayTime(0)和animationHandler.start()這兩個(gè)方法 setCurrentPlayTime(0)方法: public void setCurrentPlayTime(long playTime) { ? ? ? ? ? ? ?initAnimation(); ? ? ? ? long currentTime = AnimationUtils.currentAnimationTimeMillis(); ? ? ? ? if (mPlayingState != RUNNING) { ? ? ? ? ? ? ? mSeekTime = playTime; ? ? ? ? ? ? ? mPlayingState = SEEKED; ? ? ? ? } ? ? ? ? mStartTime = currentTime - playTime; ? ? ? ? ? ? ? doAnimationFrame(currentTime); } 上邊 ? 處的initAnimation()方法: //?ObjectAnimator 復(fù)寫了父類的initAnimation()方法 void initAnimation() { ? ? ? ? if (!mInitialized) {?// 此時(shí) mInitialized的值為false,運(yùn)行下邊邏輯 ? ? ? ? ? ??// mValueType may change due to setter/getter setup; do this before calling super.init(), ? ? ? ? ? ? // which uses mValueType to set up the default type evaluator. ? ? ? ? ? ? int numValues = mValues.length; ? ? ? ? ? ? for (int i = 0; i < numValues; ++i) {? ? ? ? ? ? ? ? ? ?? ? ? mValues[i].setupSetterAndGetter(mTarget); ? ? ? ? ? ? } ? ? ? ? ? ? ? ?? super.initAnimation(); ? ? ? ? } ? ? } 上邊第 ? 步運(yùn)行的是PropertyValuesHolder的setupSetterAndGetter()方法。來看詳細(xì)邏輯: [java] ?view plaincopy
void ?setupSetterAndGetter(Object?target)?{?? ????if ?(mProperty?!=? null )?{?? ?????????? ????????try ?{?? ????????????Object?testValue?=?mProperty.get(target);?? ????????????for ?(Keyframe?kf?:?mKeyframeSet.mKeyframes)?{?? ????????????????if ?(!kf.hasValue())?{?? ????????????????????kf.setValue(mProperty.get(target));?? ????????????????}?? ????????????}?? ????????????return ;?? ????????}?catch ?(ClassCastException?e)?{?? ????????????Log.w("PropertyValuesHolder" , "No?such?property?(" ?+?mProperty.getName()?+?? ????????????????????")?on?target?object?" ?+?target?+? ".?Trying?reflection?instead" );?? ????????????mProperty?=?null ;?? ????????}?? ????}?? ?????? ????Class?targetClass?=?target.getClass();?? ????if ?(mSetter?==? null )?{?? ?????????? ????????setupSetter(targetClass);?? ????}?? ????for ?(Keyframe?kf?:?mKeyframeSet.mKeyframes)?{?? ????????if ?(!kf.hasValue())?{?? ????????????if ?(mGetter?==? null )?{?? ????????????????setupGetter(targetClass);?? ????????????????if ?(mGetter?==? null )?{?? ?????????????????????? ?????????????????????? ????????????????????return ;?? ????????????????}?? ????????????}?? ????????????try ?{?? ????????????????kf.setValue(mGetter.invoke(target));?? ????????????}?catch ?(InvocationTargetException?e)?{?? ????????????????Log.e("PropertyValuesHolder" ,?e.toString());?? ????????????}?catch ?(IllegalAccessException?e)?{?? ????????????????Log.e("PropertyValuesHolder" ,?e.toString());?? ????????????}?? ????????}?? ????}?? }?? setupSetterAndGetter()方法中,重點(diǎn)分析setupSetter(targetClass)、setupGetter(targetClass)以及kf.setValue(mGetter.invoke(target))方法 setupSetter(targetClass)方法 [java] ?view plaincopy
void ?setupSetter(Class?targetClass)?{?? ?????? ????mSetter?=?setupSetterOrGetter(targetClass,?sSetterPropertyMap,?"set" ,?mValueType);?? }?? setupGetter(Class targetClass)方法 [java] ?view plaincopy
private ? void ?setupGetter(Class?targetClass)?{?? ?????? ????mGetter?=?setupSetterOrGetter(targetClass,?sGetterPropertyMap,?"get" ,? null );?? }?? setupSetter(targetClass) 和 setupGetter(targetClass) 方法都調(diào)用了 setupSetterOrGetter 方法,僅僅是參數(shù)有所不同,第一個(gè)和第三個(gè)好理解,第二個(gè)參數(shù)是一個(gè)集合,其定義例如以下: [java] ?view plaincopy
?? ?? private ? static ? final ?HashMap<Class,?HashMap<String,?Method>>?sSetterPropertyMap?=?? ?????????new ?HashMap<Class,?HashMap<String,?Method>>();?? private ? static ? final ?HashMap<Class,?HashMap<String,?Method>>?sGetterPropertyMap?=?? ?????????new ?HashMap<Class,?HashMap<String,?Method>>();??? 第四個(gè)參數(shù)。對(duì)于 setupSetter()方法來講,傳入的是mValueType( 我們?cè)趧?chuàng)建動(dòng)畫對(duì)象時(shí)已為其賦值 ),而對(duì)于setupGetter()方法來講,傳入的是null,來看setupSetterOrGetter 方法的主要邏輯: [java] ?view plaincopy
? ? ? ?? ??? ??? private ?Method?setupSetterOrGetter(Class?targetClass,?? ????????HashMap<Class,?HashMap<String,?Method>>?propertyMapMap,?? ????????String?prefix,?Class?valueType)?{?? ????Method?setterOrGetter?=?null ;? ?? ????try ?{?? ?????????? ?????????? ?????????? ????????mPropertyMapLock.writeLock().lock();?? ????????HashMap<String,?Method>?propertyMap?=?propertyMapMap.get(targetClass);?? ????????if ?(propertyMap?!=? null )?{ ?? ????????????setterOrGetter?=?propertyMap.get(mPropertyName);?? ????????}?? ????????if ?(setterOrGetter?==? null )?{?? ?????????????? ?????????????? ?????????????? ????????????setterOrGetter?=?getPropertyFunction(targetClass,?prefix,?valueType);?? ????????????if ?(propertyMap?==? null )?{?? ????????????????propertyMap?=?new ?HashMap<String,?Method>();?? ????????????????propertyMapMap.put(targetClass,?propertyMap);?? ????????????}?? ?????????????? ????????????propertyMap.put(mPropertyName,?setterOrGetter);?? ????????}?? ????}?finally ?{?? ????????mPropertyMapLock.writeLock().unlock();?? ????}?? ????return ?setterOrGetter;?? }?? setupSetterAndGetter()方法中 ,setupSetter(targetClass)、setupGetter(targetClass)方法大致分析完了,它完畢了對(duì)mSetter和mGetter的初始化,接下來,對(duì)KeyframeSet的成員變量ArrayList<Keyframe> mKeyframes (上文分析過,在屬性動(dòng)畫的對(duì)象創(chuàng)建時(shí),就以完畢對(duì)mKeyframes的初始化。mKeyframes里邊放的是依據(jù)傳入的value構(gòu)造出的動(dòng)畫運(yùn)行過程中的幀對(duì)象) 進(jìn)行遍歷。詳細(xì)邏輯是: for (Keyframe kf : mKeyframeSet.mKeyframes) { ? ? ? ? ? ? if (!kf.hasValue() ) {?//? hasValue()方法定義例如以下: public boolean hasValue() { ? ? ? ? return mHasValue;?//?Keyframe的成員變量。 boolean mHasValue ,默認(rèn)是 false // 上文我們?cè)谥v動(dòng)畫創(chuàng)建過程中 依據(jù)傳入的 values 構(gòu)造出? keyframes 數(shù)組中的每一項(xiàng)(關(guān)鍵幀對(duì)象 Keyframe )時(shí),已經(jīng)講過, //? 假設(shè)我們僅僅傳入了一個(gè)參數(shù),那么這個(gè)參數(shù)將用于構(gòu)建 keyframes[1],走下邊的第一個(gè)構(gòu)造函數(shù) //?keyframes[0]的值則由 ofFloat(0f)來構(gòu)建,走下邊的第二個(gè)構(gòu)造函數(shù),即此關(guān)鍵幀對(duì)象的mHasValue為默認(rèn)值false FloatKeyframe(float fraction, float value) { ? ? ? ? ? ? mFraction = fraction; ? ? ? ? ? ? mValue = value; ? ? ? ? ? ? mValueType = float.class; ? ? ? ? ? ??mHasValue = true;? // 標(biāo)示一個(gè)幀對(duì)象是否已有value值 } FloatKeyframe(float fraction) { ? ? ? ? ? ? mFraction = fraction; ? ? ? ? ? ? mValueType = float.class; } } ? ? ? ? ? ? ? ? if (mGetter == null) { ? ? ? ? ? ? ? ? ? ? ? ??setupGetter(targetClass); ?// 上文已分析過了 ? ? ? ? ? ? ? ? ? ? ? ? if (mGetter == null) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // Already logged the error - just return to avoid NPE ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return; ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? ? ??kf.setValue(mGetter.invoke(target)); // 該方法利用通過反射獲得的get方法為 mKeyframes集合中還沒有value值的幀對(duì)象賦值 // 上文中,講到 Keyframe ?對(duì)象的創(chuàng)建時(shí)。構(gòu)造函數(shù)? public static Keyframe ofFloat(float fraction)的凝視為: //? Constructs a Keyframe object with the given time. The value at this time will be derived ?from the target object when ? // the animation first starts ... ... 指的就是這個(gè)地方 public void setValue(Object value) { ? ? ? ? ? ? if (value != null && value.getClass() == Float.class) { ? ? ? ? ? ? ? ? mValue = ((Float)value).floatValue(); ? ? ? ? ? ? ? ? mHasValue = true; ? ? ? ? ? ? } } ? ? ? ? ? ? ? ? ?} catch (InvocationTargetException e) { ? ? ? ? ? ? ? ? ? ? ? ? Log.e("PropertyValuesHolder", e.toString()); ? ? ? ? ? ? ? ? ?} catch (IllegalAccessException e) { ? ? ? ? ? ? ? ? ? ? ? ? Log.e("PropertyValuesHolder", e.toString()); ? ? ? ? ? ? ? ? ?} ? ? ? ? ? } } 至此,上邊第 ? 步運(yùn)行完了,它主要是對(duì)動(dòng)畫對(duì)象的成員變量PropertyValuesHolder[] mValues做更進(jìn)一步的初始化,接下來運(yùn)行上文中的第 ? 步,父類ValueAnimator中定義的initAnimation()方法 /** ? ? ?* This function is called immediately before processing the first animation?frame of an animation. If there is a nonzero ? ? ?* ?<code>startDelay</code>, the?function is called after that delay ends.It takes care of the final initialization steps for the ? ? ?*?animation. ... ?... ? ? ?*/ ? ???// 這種方法在運(yùn)行動(dòng)畫的第一幀之前被調(diào)用。假設(shè)有一個(gè)不為零的startDelay值,該方法將在對(duì)應(yīng)的延遲時(shí)間執(zhí)后被運(yùn)行 ? ? ?// 這是一個(gè)動(dòng)畫最后的初始化步驟 ... ... void initAnimation() { ? ? ? ? if (!mInitialized) { ? ? ? ? ? ? ? ?int numValues = mValues.length; ? ? ? ? ? ? ? ?for (int i = 0; i < numValues; ++i) { ? ? ? ? ? ? ? ? ? ? ?mValues[i].init(); /** ? ? ?* Internal function, called by ValueAnimator, to set up the TypeEvaluator that will be used? to?calculate animated values.? ? ? ?*/ ? ? ?// 邏輯非常easy。就是依據(jù)mValueType的值設(shè)置成員變量TypeEvaluator mEvaluator? 的值,用來 calculate animated values void init() { if (mEvaluator == null) { ? ? ? ? ? ? ???// We already handle int and float automatically, but not their Object ? ? ? ? ? ? ? ?// equivalents ? ? ? ? ? ? ? ?mEvaluator = (mValueType == Integer.class) ? sIntEvaluator : ? ? ? ? ? ? ? ? ? ? (mValueType == Float.class) ? sFloatEvaluator :
? ? ? ? ? ? ? ? ? ? null; ? ? ? ? } ? ? ? ? if (mEvaluator != null) { ? ? ? ? ? ? ? ? ?// KeyframeSet knows how to evaluate the common types - only give it a custom ? ? ? ? ? ? ? ? ?// evaluator if one has been set on this class ? ? ? ? ? ? ? ? ?mKeyframeSet.setEvaluator(mEvaluator); ? ? ? ? ?} } ? ? ? ? ? ? ? ?} ? ? ?? ? ? ?// 如今,動(dòng)畫最后的初始化已經(jīng)完畢,就將? mInitialized 的值設(shè)為 true 了 ? ? ? ? ? ? ? ?mInitialized = true; ? ? ? ? } } 到如今。上文中第 ? 步也完畢了,我們能夠看到,這一步是在做進(jìn)一步的初始化, 當(dāng)中對(duì)set和get方法的初始化和為沒有value值得幀對(duì)象賦值的操作是在ObjectAnimator中完畢的。而對(duì)用來計(jì)算動(dòng)畫的value值的TypeEvaluator的初始化則是在ValueAnimator中完畢的 稍后再來分析上文中第 ? 步的doAnimationFrame(currentTime)方法,因此,在ValueAnimator的start( )方法中,須要重點(diǎn)分析的兩個(gè)方法之中的一個(gè)setCurrentPlayTime(0)就到此為止。 接著看后邊的animationHandler.start(): animationHandler.start()方法終于會(huì)導(dǎo)致AnimationHandler的run方法的運(yùn)行 (此處細(xì)節(jié)省略): [java] ?view plaincopy
public ? void ?run()?{?? ????mAnimationScheduled?=?false ;?? ?????? ????doAnimationFrame(mChoreographer.getFrameTime());?? }?? doAnimationFrame( )方法: private void doAnimationFrame(long frameTime) { ? ? ? ? ? ??// mPendingAnimations holds any animations that have requested to be started ? ? ? ? ? ? // We're going to clear mPendingAnimations, but starting animation may ? ? ? ? ? ? // cause more to be added to the pending list (for example, if one animation ? ? ? ? ? ? // starting triggers another starting). So we loop until mPendingAnimations ? is empty. ? ? ? ? ? ? while (mPendingAnimations.size() > 0) { ? ? ? ? ? ? ? ? ? ?ArrayList<ValueAnimator> pendingCopy =? (ArrayList<ValueAnimator>) mPendingAnimations.clone(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?mPendingAnimations.clear(); ? ? ? ? ? ? ? ? ? ?int count = pendingCopy.size(); ? ? ? ? ? ? ? ? ? ?for (int i = 0; i < count; ++i) { ? ? ? ? ? ? ? ? ? ? ? ? ?ValueAnimator anim = pendingCopy.get(i); ? ? ? ? ? ? ? ? ? ? ? ???// If the animation has a startDelay, place it on the delayed list ? ? ? ? ? ? ? ? ? ? ? ? ?if (anim.mStartDelay == 0) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?anim.startAnimation(this); ? ? ? ?// 事實(shí)上。上述代碼最基本的就是運(yùn)行了一句? handler.mAnimations.add(this); ? ? ? ? ? ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mDelayedAnims.add(anim); ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? } ? ? ? ? ? ??// Next, process animations currently sitting on the delayed queue, adding? them to the active animations if they are ready? ? ? ? ? ? ? int numDelayedAnims = mDelayedAnims.size(); ? ? ? ? ? ? for (int i = 0; i < numDelayedAnims; ++i) { ? ? ? ? ? ? ? ? ? ?ValueAnimator anim = mDelayedAnims.get(i); ? ? ? ? ? ? ? ? ? ?if (anim.delayedAnimationFrame(frameTime)) { ? ? ? ? ? ? ? ? ? ? ? ? ?mReadyAnims.add(anim); ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? } ? ? ? ? ? ? int numReadyAnims = mReadyAnims.size(); ? ? ? ? ? ? if (numReadyAnims > 0) { ? ? ? ? ? ? ? ? ? ?for (int i = 0; i < numReadyAnims; ++i) { ? ? ? ? ? ? ? ? ? ? ? ? ?ValueAnimator anim = mReadyAnims.get(i); ? ? ? ? ? ? ? ? ? ? ? ? ?anim.startAnimation(this); ? ? ? ? ? ? ? ? ? ? ? ? ?anim.mRunning = true; ? ? ? ? ? ? ? ? ? ? ? ? ?mDelayedAnims.remove(anim); ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ?mReadyAnims.clear(); ? ? ? ? ? ? } ? ? ? ? ??? //Now process all active animations. The return value from animationFrame() ? tells the handler whether it should now be ended ? ? ? ? ? ? int numAnims = mAnimations.size(); ? ? ? ? ? ? for (int i = 0; i < numAnims; ++i) { ? ? ? ? ? ? ? ? ? ?mTmpAnimations.add(mAnimations.get(i)); ? ? ? ? ? ? } ? ? ? ? ? ? for (int i = 0; i < numAnims; ++i) { ? ? ? ? ? ? ? ? ? ?ValueAnimator anim = mTmpAnimations.get(i); ? ? ? ? ? ? ? ? ? ?if (mAnimations.contains(anim) && ? ? ? ? anim.doAnimationFrame(frameTime) ) { ? ? ? ? ? ? ? ? ? ? ? ? ?mEndingAnims.add(anim); ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? } ? ? ? ? ? ? mTmpAnimations.clear(); ? ? ? ? ? ? if (mEndingAnims.size() > 0) { ? ? ? ? ? ? ? ? ? ?for (int i = 0; i < mEndingAnims.size(); ++i) { ? ? ? ? ? ? ? ? ? ? ? ? ?mEndingAnims.get(i).endAnimation(this); ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ?mEndingAnims.clear(); ? ? ? ? ? ? } ? ? ? ? ? ??// If there are still active or delayed animations, schedule a future call to ? onAnimate to process the next frame of the animations. ? ? ? ? ? ??if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) { ? ? ? ? ? ? ? ? scheduleAnimation(); ? ? ? ? ? ? } } 能夠看到。在AnimationHandler類中。有下面幾個(gè)集合: [java] ?view plaincopy
?? protected ? final ?ArrayList<ValueAnimator>?mAnimations?=? new ?ArrayList<ValueAnimator>();?? ?? private ? final ?ArrayList<ValueAnimator>?mTmpAnimations?=? new ?ArrayList<ValueAnimator>();?? ?? protected ? final ?ArrayList<ValueAnimator>?mPendingAnimations?=? new ?ArrayList<ValueAnimator>();?? protected ? final ?ArrayList<ValueAnimator>?mDelayedAnims?=? new ?ArrayList<ValueAnimator>();?? private ? final ?ArrayList<ValueAnimator>?mEndingAnims?=? new ?ArrayList<ValueAnimator>();?? private ? final ?ArrayList<ValueAnimator>?mReadyAnims?=? new ?ArrayList<ValueAnimator>();?? 在AnimationHandler類的doAnimationFrame( )方法中,會(huì)依據(jù)動(dòng)畫的屬性值的變化。用這些集合來管理動(dòng)畫對(duì)象,而且在這個(gè)過程中。會(huì)調(diào)用到最核心的ValueAnimator類的doAnimationFrame()方法 (第? ? ? 步) , 當(dāng)mAnimations.contains(anim)而且doAnimationFrame()方法的返回值為true時(shí)。 就會(huì)運(yùn)行mEndingAnims.add(anim);將動(dòng)畫對(duì)象加入到mEndingAnims集合中,接著,遍歷mEndingAnims集合,運(yùn)行?mEndingAnims.get(i).endAnimation(this);主要是將mAnimations、mPendingAnimations、mDelayedAnims集合中的對(duì)象清空以及改變一些標(biāo)示。標(biāo)示著動(dòng)畫的結(jié)束。 假設(shè)doAnimationFrame()方法的返回值為false。 則在滿足條件 (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty())? 時(shí)。 運(yùn)行scheduleAnimation(),即相當(dāng)于調(diào)用animationHandler.start()繼續(xù)循環(huán)。
那么doAnimationFrame()方法的邏輯是什么? 又回到了在上文中。當(dāng)時(shí)我們臨時(shí)放下沒有分析的第 ? 步中的doAnimationFrame(currentTime)方法上: [java] ?view plaincopy
final ? boolean ?doAnimationFrame( long ?frameTime)?{?? ????if ?(mPlayingState?==?STOPPED)?{???}?? ????if ?(mPaused)?{??}?? ????else ? if ?(mResumed)?{?????}?? ?????? ????final ? long ?currentTime?=?Math.max(frameTime,?mStartTime);?? ????return ?animationFrame(currentTime);?? }?? 接著是 animationFrame()方法: boolean animationFrame(long currentTime) { boolean done = false; switch (mPlayingState) {
? ? ? ? ? ? ??case RUNNING: ? ? ? ? ? ? ?case SEEKED: ? ? ? ?? float fraction ?= mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f; if (fraction >= 1f) { if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) { // Time to repeat if (mListeners != null) { int numListeners = mListeners.size(); for (int i = 0; i < numListeners; ++i) { mListeners.get(i).onAnimationRepeat(this); } } if (mRepeatMode == REVERSE) { mPlayingBackwards = !mPlayingBackwards; } mCurrentIteration += (int)fraction; fraction = fraction % 1f; mStartTime += mDuration; } else {
done = true; fraction = Math.min(fraction, 1.0f); } } if (mPlayingBackwards) { fraction = 1f - fraction; }
? ? ? ? ? ?? ? ? ? animateValue(fraction); break; } return done; }
我們看到。在每一次調(diào)用該方法時(shí)。都會(huì)依據(jù)動(dòng)畫對(duì)象的一些和時(shí)間相關(guān)的屬性的值來計(jì)算 fraction 的值,來推斷要返回true還是false。 從代碼中。能夠看出,fraction代表的就是動(dòng)畫運(yùn)行過程中的每一幀在整個(gè)動(dòng)畫運(yùn)行過程中所處的時(shí)間的比率。
分析到此。整個(gè)屬性動(dòng)畫的實(shí)現(xiàn)原理基本清楚了,還剩最后一點(diǎn) —— 每一次調(diào)用animationFrame方法時(shí),怎么利用計(jì)算出來的 fraction 來改變動(dòng)畫作用對(duì)象的屬性值以達(dá)到動(dòng)畫的效果?答案是上文中 ? 處的animateValue(fraction)方法,須要注意的是,ObjectAnimator類重寫了父類的animateValue(fraction)方法,來看詳細(xì)邏輯: void animateValue(float fraction) { ? ? ? ??super.animateValue(fraction);? // 首先調(diào)用父類的方法 ? ? ? ? int numValues = mValues.length; ? ? ? ? for (int i = 0; i < numValues; ++i) { ? ? ? ? ? ??mValues[i].setAnimatedValue(mTarget); void setAnimatedValue(Object target) { ? ? ? ? if (mProperty != null) { ? ? ? ? ? ? mProperty.set(target, getAnimatedValue()); ? ? ? ? } ? ? ? ? if (mSetter != null) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? mTmpValueArray[0] = getAnimatedValue(); ? ? ? ? ? ? ? ??mSetter.invoke(target, mTmpValueArray); ? ? ? ? ? ? } catch (InvocationTargetException e) { ? ? ? ? ? ? ? ? Log.e("PropertyValuesHolder", e.toString()); ? ? ? ? ? ? } catch (IllegalAccessException e) { ? ? ? ? ? ? ? ? Log.e("PropertyValuesHolder", e.toString()); ? ? ? ? ? ? } ? ? ? ? } } ? ? ? ? } } 父類ValueAnimator的animateValue(fraction)方法: void animateValue(float fraction) { ??// 此時(shí)。我們?cè)谖恼碌拈_頭提到的插值器登場了 ? ? ? ? fraction =?mInterpolator .getInterpolation(fraction); private TimeInterpolator?mInterpolator? =?sDefaultInterpolator ; private static final TimeInterpolator?sDefaultInterpolator ?=?new AccelerateDecelerateInterpolator(); ?// 能夠看到,假設(shè)不進(jìn)行設(shè)置的話,默認(rèn)的插值器就是?AccelerateDecelerateInterpolator ? ?? ? ? ?? ? ? ? ? mCurrentFraction = fraction; ? ? ? ? int numValues = mValues.length; ? ? ? ? for (int i = 0; i < numValues; ++i) { ? ? ? ?// 細(xì)節(jié)省略了 ? ? ? ? ? ? ? ?mValues[i].calculateValue(fraction); ? ? ? ? } ? ? ? ? if (mUpdateListeners != null) { ? ? ? ? ? ? ? ?int numListeners = mUpdateListeners.size(); ? ? ? ? ? ? ? ?for (int i = 0; i < numListeners; ++i) { ? ? ? ? ? ? ? ? ? ? ?mUpdateListeners.get(i).onAnimationUpdate(this); ? ? ? ? ? ? ? ?} ? ? ? ? } } 至此,屬性動(dòng)畫實(shí)現(xiàn)原理基本清楚了。
轉(zhuǎn)載于:https://www.cnblogs.com/gccbuaa/p/7295246.html
總結(jié)
以上是生活随笔 為你收集整理的Android - Animation(二) 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。