日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android - Animation(二)

發布時間:2024/9/5 Android 88 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android - Animation(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Android - Animation(一)?一文總結了Android中的補間動畫View?Animation/Tween Animation)和幀動畫Drawable?Animation/Frame Animation)的使用

本篇文章主要解析屬性動畫(Property Animation,android3.0引入)的實現原理


? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 下篇 ? 屬性動畫的實現原理


先來看屬性動畫的最簡單實現:

第一種方式:先在?/res/animator/文件夾下創建translate.xml文件定義動畫。再在Java文件里引用并開啟 [java]?view plaincopy
  • //?首先在/res/animator/文件夾下創建translate.xml文件。內容例如以下:??
  • <?

    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>??
  • ??
  • //然后在Java文件里進行引用。代碼例如以下:??
  • mButton1?=?(Button)?findViewById(R.id.button1);??
  • mButton1.setOnClickListener(this);??
  • //載入xml文件里的動畫資源??
  • 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文件里創建并使用動畫 [java]?view plaincopy
  • mButton1?=?(Button)?findViewById(R.id.button1);??
  • mButton1.setOnClickListener(this);??
  • public?void?onClick(View?v)?{??
  • ????//利用ofFloat()方法創建動畫、指定須要改變的屬性的名稱等并開啟動畫??
  • ????ObjectAnimator.ofFloat(mButton1,?"translationX",?0.0f,20.0f).setDuration(3000).start();??
  • }??
  • 簡單地說,屬性動畫就是在指定的時間內改變對象的屬性值。

    上述的樣例。從代碼上看,設置了動畫運行的時間、作用的目標對象mButton1及其屬性translationX以及屬性值的初始值和終于值,但從效果上看,mButton1在2秒鐘之內在屏幕上勻速的移動了一段距離。于是我們能夠猜想:

    在start()方法運行之后。是不是會不斷地計算出一個值并賦給目標對象的屬性? 在屬性動畫中。是不是也有和補間動畫里類似的插值器來改變動畫的運行速率? 假設有這種一個插值器的話,須要賦給目標對象的屬性的那個值的計算是不是也和這個插值器有關? ... ... 帶著這些猜想,我們就以?在Java文件里創建動畫的方式?為例來梳理屬性動畫的實現原理。


    首先是ObjectAnimator類的靜態方法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). 創建并返回 一個基于float?類型數值的ObjectAnimator?對象,一個value值代表動畫的終點,兩個value?值,則一個是起點, 還有一個是終點,假設是多個值,則中間的值代表動畫將要經過的點?,而且這些點會均勻地分布在動畫的運行過程中 */ public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) { ? ? ? ? ObjectAnimator anim = newObjectAnimator(target, propertyName); ? ? ? ????anim.setFloatValues(values); ??? ? ? return anim; }

    ObjectAnimator的構造函數: [java]?view plaincopy
  • private?ObjectAnimator(Object?target,?String?propertyName)?{??
  • ????//為ObjectAnimator的成員變量private?Object?mTarget賦值,mTarget的凝視為:??
  • ????//The?target?object?on?which?the?property?exists,?set?in?the?constructor??
  • ????mTarget?=?target;??
  • ????setPropertyName(propertyName);??
  • }??
  • setPropertyName方法: [java]?view plaincopy
  • public?void?setPropertyName(String?propertyName)?{??
  • ????//?mValues?could?be?null?if?this?is?being?constructed?piecemeal.?Just?record?the???
  • ????//?propertyName?to?be?used?later?when?setValues()?is?called?if?so.??
  • ????//mValues是ObjectAnimator的父類ValueAnimator的成員變量PropertyValuesHolder[]?mValues;??
  • ????//第一次運行為null??
  • ????if?(mValues?!=?null)?{??
  • ????????PropertyValuesHolder?valuesHolder?=?mValues[0];??
  • ????????String?oldName?=?valuesHolder.getPropertyName();??
  • ????????valuesHolder.setPropertyName(propertyName);??
  • ????????mValuesMap.remove(oldName);??
  • ????????mValuesMap.put(propertyName,?valuesHolder);??
  • ????}??
  • ????//為ObjectAnimator的成員變量private?String?mPropertyName賦值??
  • ????mPropertyName?=?propertyName;??
  • ????//?New?property/values/target?should?cause?re-initialization?prior?to?starting??
  • ????//mInitialized?是ObjectAnimator的父類ValueAnimator的成員變量boolean?mInitialized;??
  • ????//它的凝視為:Flag?that?denotes?whether?the?animation?is?set?up?and?ready?to?go.???
  • ????//Used?to?set?up?animation?that?has?not?yet?been?started.??
  • ????//一個Flag用于標示動畫是否開始準備運行,它被用于動畫還沒有正式開始start之前。

    默認值為false

    ??
  • ????mInitialized?=?false;??
  • }??
  • 所以。第一次運行ObjectAnimator anim = new ObjectAnimator(target, propertyName);僅僅做了兩件事情: 1、為ObjectAnimator?的成員變量mTarget和mPropertyName賦值 2、將mInitialized(定義在ObjectAnimator?的父類?ValueAnimator 中)的值設為false 接下來是上文中?處的anim.setFloatValues(values)方法: @Override public void setFloatValues(float... values) { if (mValues == null || mValues.length == 0) {?//第一次運行mValues == null // No values yet - this animator is being constructed piecemeal. Init the values with?whatever the current propertyName is ? ? ? ??//?mValues眼下尚未賦值——當前的animator?正在構建中,將通過傳入的values初始化mValues if (mProperty != null) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? //mProperty?為ObjectAnimator的成員變量?private Property mProperty,第一次運行時也為null ? ? ? ? ? ? ? ? ? ? ? ? ? ? setValues(PropertyValuesHolder.ofFloat(mProperty, values)); } else { ? ? ?? ? ? ? ? ? ? ? ? ? ? // 第一次運行時。下列函數將被調用: ?setValues(PropertyValuesHolder.ofFloat(mPropertyName, values)); } } else { super.setFloatValues(values); } }

    在分析setValues()方法之前先來看PropertyValuesHolder的ofFloat()方法:

    /** * Constructs and returns a PropertyValuesHolder with a given property name and?set of float values. */ ?// 通過給定的propertyName 和 values創建并返回一個PropertyValuesHolder?對象 public static PropertyValuesHolder ofFloat(String propertyName, float... values) { ? ??? ???return new FloatPropertyValuesHolder(propertyName, values); } 接著FloatPropertyValuesHolder的構造函數:

    public FloatPropertyValuesHolder(String propertyName, float... values) { super(propertyName); ? ? ? ????setFloatValues(values); } 首先運行的是FloatPropertyValuesHolder 的父類 PropertyValuesHolder的構造函數:

    [java]?view plaincopy
  • private?PropertyValuesHolder(String?propertyName)?{??
  • ????//?為成員變量String?mPropertyName(定義在PropertyValuesHolder類中)賦值??
  • ????mPropertyName?=?propertyName;??
  • }??
  • 我們注意到,FloatPropertyValuesHolder?、IntPropertyValuesHolder都是PropertyValuesHolder的靜態內部類 來看一下PropertyValuesHolder的類定義: [java]?view plaincopy
  • /**?
  • ?*?This?class?holds?information?about?a?property?and?the?values?that?that?property?should?take?on?during?an?animation.??
  • ?*?PropertyValuesHolder?objects?can?be?used?to?create?animations?with?ValueAnimator?or?ObjectAnimator?that?operate?on?several?????
  • ?*?different?properties?in?parallel.?
  • ?*/??
  • ??//這個類維持著一個property?和它的?值,用以在動畫中呈現出來,??
  • ??//我們能夠覺得它是為實現屬性動畫而對property及其值做的一個包裝??
  • public?class?PropertyValuesHolder?implements?Cloneable?{?}??
  • 接下來是上文中?處setFloatValues()方法:

    @Override public void setFloatValues(float... values) { ? ? ? ??? ????super.setFloatValues(values); ? ? ? ? ? ? mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet; } 首先運行的又是父類的方法:

    public void setFloatValues(float... values) { ? ? ? ? // 為成員變量Class?mValueType(定義在父類PropertyValuesHolder中)賦值 ? ? ? ? mValueType = float.class;? ? ? ? ???mKeyframeSet = KeyframeSet.ofFloat(values); }

    然后,mKeyframeSet = KeyframeSet.ofFloat(values),先來看KeyframeSet類的定義:

    [java]?view plaincopy
  • /**?
  • ?*?This?class?holds?a?collection?of?Keyframe?objects?and?is?called?by?ValueAnimator?to?calculate?
  • ?*?values?between?those?keyframes?for?a?given?animation.?The?class?internal?to?the?animation?
  • ?*?package?because?it?is?an?implementation?detail?of?how?Keyframes?are?stored?and?used.?
  • ?*/??
  • ?//這個類維持著一個Keyframe?對象的集合,??
  • ?//ValueAnimator使用它來為一個動畫計算那些?keyframe?之間的值?...?...??
  • class?KeyframeSet?{?}??
  • 對KeyframeSet有一個大概了解之后。再來看一下Keyframe類的定義:

    [java]?view plaincopy
  • /**?
  • ?*?This?class?holds?a?time/value?pair?for?an?animation.?The?Keyframe?class?is?used?by?{@link?ValueAnimator}?to?define?the?values?that?
  • ?*??the?animation?target?will?have?over?the?course?of?the?animation.?As?the?time?proceeds?from?one?keyframe?to?the?other,?the?value?of?
  • ?*??the?target?object?will?animate?between?the?value?at?the?previous?keyframe?and?the?value?at?the?next?keyframe.?Each?keyframe?also??
  • ?*?holds?an?optional?{@link?TimeInterpolator}?object,?which?defines?the?time?interpolation?over?the?intervalue?preceding?the?keyframe.?
  • ?*/??
  • ?//簡單說。這就是個?對動畫過程中的一幀的時間和屬性的值進行封裝的類??
  • public?abstract?class?Keyframe?implements?Cloneable?{?}??
  • 來看上文中?處的KeyframeSet的ofFloat(values)方法:

    public static KeyframeSet ofFloat(float... values) { ? ? ? ? boolean badValue = false;//初始化一個標示。之后用于標示values[i]是不是一個數字 ? ? ? ? int numKeyframes = values.length;//獲取傳入的參數的個數 ? ? ? ? //初始化一個FloatKeyframe?類型的數組,數組的長度為numKeyframes和2之間的較大者,這個比較easy理解 ? ? ? ??FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)]; ? ? ? ? if (numKeyframes == 1) { ? ?? ???//假設我們僅僅傳入了一個參數,那么這個參數將用于構建keyframes[1]。keyframes[0]的值則由ofFloat(0f)來構建。例如以下: ? ? ? ? ? ? ??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構造一個Keyframe?對象。在動畫第一次運行時。這個給定的時間相應的value將利用動畫的目標對象去獲得 ... ... public static Keyframe ofFloat(float fraction) { ? ? ? ? //FloatKeyframe和IntKeyframe都是Keyframe?的靜態內部類。這個和PropertyValuesHolder結構是類似的 ? ? ? ? return new FloatKeyframe(fraction); FloatKeyframe(float fraction) { ?// 為成員變量float mFraction(定義在Keyframe?中)賦值,?注意,在此時。成員變量mValue的值還沒有設置? 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構造一個Keyframe?對象,time作為整個動畫運行過程中的一個時間比例。是一個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;?// 假設傳入的值不是一個數值,將標示badValue改為true ? ? ? ? ? ?} //從以上分析能夠看到。當我們僅僅傳入一個值時,將用1(代表時間終點)和這個值構建出動畫運行的最后一幀的Keyframe //?對象。而動畫的第一幀相應的Keyframe?對象,則默認由0(代表時間的起點)來構建,這一幀相應的值將在動畫第一次 //運行時由動畫作用的對象來獲得,假設我們傳入的參數大于1個,比方2個或者多個。則運行下邊的邏輯: ? ? ? ? ? ?} else { //邏輯比較簡單,假設傳入的參數大于1,則,用0f和values[0]構建出動畫的第一幀相應的Keyframe對象并賦值給keyframes[0], //代表第一個value相應動畫的起始值 ? ? ? ? ? ? ? ? ?keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]); // 然后。進行遍歷,利用values[i] 和 其所相應的幀在整個動畫運行過程中應該處于的時間比例——? //?(float) i / (numKeyframes - 1)?來構建每個Keyframe對象。一般我們傳入的參數是兩個。所以第二個參數就相應了 // 動畫運行的最后一幀的屬性值。事實上,在這里,屬性動畫實現的原理已經開始有所體現了。 ? ? ? ? ? ? ? ? ?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;// 同上,假設傳入的值不是一個數值,將標示badValue改為true ? ? ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ?} ? ? ? ? ? } ? ? ? ? ? if (badValue) { ? ? ? ? ? ? ? ? ? Log.w("Animator", "Bad value (NaN) in float animator");// 假設傳入的值不是一個數值,運行此邏輯 ? ? ? ? ? ?} //以上邏輯主要就是創建keyframes數組。該數組中放的是依據傳入的value值創建出來的動畫運行過程中的關鍵幀對象 //即(主要是)將一個mKeyframes?成員變量完畢初始化的FloatKeyframeSet對象返回 ? ? ? ? ??return new FloatKeyframeSet(keyframes); public FloatKeyframeSet(FloatKeyframe... keyframes) { ? ? ? ??// 走的是父類的構造函數 ? ? ? ? super(keyframes); public KeyframeSet(Keyframe... keyframes) { ? ? ? ? //這個邏輯就比較簡單了 ? ? ? ? mNumKeyframes = keyframes.length;//為成員變量int mNumKeyframes()賦值 ? ? ? ? mKeyframes = new ArrayList<Keyframe>(); ? ? ? ? //將接收到的keyframes數組中的元素加入到成員變量ArrayList<Keyframe> mKeyframes集合中 ? ? ? ??mKeyframes.addAll(Arrays.asList(keyframes)); ? ? ? ? mFirstKeyframe = mKeyframes.get(0);// 初始化第一幀相應的成員變量Keyframe mFirstKeyframe ? ? ? ? mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);?// 初始化最后一幀相應的成員變量Keyframe?mLastKeyframe ? ? ? ??// 初始化插值器相應的成員變量TimeInterpolator mInterpolator,眼下為null ? ? ? ? mInterpolator = mLastKeyframe.getInterpolator(); private TimeInterpolator mInterpolator = null; public TimeInterpolator getInterpolator() { ? ? ? ? return mInterpolator; } } } }

    至此,KeyframeSet的ofFloat(values)方法完畢了,基本的邏輯是:

    依據傳入的value值創建出動畫運行過程中的關鍵幀對象,將這些對象放在一個數組中,new一個FloatKeyframeSet對象,然后將數組中的這些元素,放在FloatKeyframeSet對象的成員變量ArrayList<Keyframe> mKeyframes中,并將FloatKeyframeSet對象返回。
    上邊第?步將這個FloatKeyframeSet對象賦值給PropertyValuesHolder的成員變量KeyframeSet mKeyframeSet,于是。第?步也運行完了,接著。在setFloatValues()方法中。運行完第?步后: [java]?view plaincopy
  • mFloatKeyframeSet?=?(FloatKeyframeSet)?mKeyframeSet;??
  • //將mKeyframeSet向下轉型為FloatKeyframeSet賦值給FloatPropertyValuesHolder??
  • //的成員變量FloatKeyframeSet?mFloatKeyframeSet??
  • 于是。第?步也運行完了,第?步把完畢初始化的FloatPropertyValuesHolder對象返回,第?步將利用第?步返回的對象作為參數。運行setValues()方法。(該方法在ObjectAnimator的父類ValueAnimator類中定義),詳細邏輯例如以下:

    [java]?view plaincopy
  • public?void?setValues(PropertyValuesHolder...?values)?{??
  • ????int?numValues?=?values.length;??
  • ????//?為PropertyValuesHolder[]?mValues(在ObjectAnimator父類ValueAnimator中定義)賦值??
  • ????mValues?=?values;??
  • ????//?為成員變量HashMap<String,?PropertyValuesHolder>?mValuesMap賦值,??
  • ????//下面是關于mValuesMap的凝視:??
  • ????//A?hashmap?of?the?PropertyValuesHolder?objects.?This?map?is?used?to?lookup???
  • ????//animated?values?by?property?name?during?calls?to?getAnimatedValue(String).??
  • ????//一個用于存儲PropertyValuesHolder對象的集合。在調用getAnimatedValue(String)方法??
  • ????//時通過property?name來查找values???
  • ????mValuesMap?=?new?HashMap<String,?PropertyValuesHolder>(numValues);??
  • ????for?(int?i?=?0;?i?<?numValues;?++i)?{??
  • ????????PropertyValuesHolder?valuesHolder?=?values[i];??
  • ????????mValuesMap.put(valuesHolder.getPropertyName(),?valuesHolder);??
  • ????}??
  • ????//?New?property/values/target?should?cause?re-initialization?prior?to?starting??
  • ????mInitialized?=?false;??
  • }??


  • 至此,用于創建屬性動畫對象的ObjectAnimator類的靜態方法ofFloat的大體邏輯分析完畢了。

    簡單總結一下:

    ObjectAnimator.ofFloat(Object target, String propertyName, float... values)?創建了一個ObjectAnimator對象,而且: 1、將?target 賦給 ObjectAnimator 的成員變量?private Object mTarget 2、將?propertyName 賦給?ObjectAnimator 的成員變量?private String mPropertyName 3、創建一個 FloatPropertyValuesHolder 對象 3.1、將?propertyName 賦給?FloatPropertyValuesHolder 的成員變量?String mPropertyName(在FloatPropertyValuesHolder?的父類?PropertyValuesHolder中定義 3.2、將?float.class?賦給?FloatPropertyValuesHolder 的成員變量?Class mValueType(在FloatPropertyValuesHolder?的父類?PropertyValuesHolder中定義 3.3、創建一個?FloatKeyframeSet對象 3.3.1、創建一個 FloatKeyframe 類型的數組 keyframes? 3.3.2、依據傳入的 values 構造出?keyframes 數組中的每一項(關鍵幀對象Keyframe 3.3.3、將?keyframes 數組中的每一項加入到?FloatKeyframeSet 對象的成員變量? ? ?ArrayList<Keyframe>mKeyframes(在FloatKeyframeSet?的父類KeyframeSet中定義)中 3.4、將?FloatKeyframeSet 對象賦給?PropertyValuesHolder 的成員變量?KeyframeSet mKeyframeSet 3.5、將?mKeyframeSet 向下轉型為?FloatKeyframeSet 類型賦給? FloatPropertyValuesHolder 的成員變量?FloatKeyframeSet mFloatKeyframeSet 4、將?FloatPropertyValuesHolder 對象?賦給ObjectAnimator 的成員變量?PropertyValuesHolder[] mValues ? ?(在ObjectAnimator?的父類ValueAnimator中定義 5、利用已完畢初始化的FloatPropertyValuesHolder?對象及其mPropertyName屬性。 ? ? ?完畢成員變量HashMap<String, PropertyValuesHolder> mValuesMap(在ValueAnimator中定義)的初始化
    動畫開始運行之前。另一個關鍵的方法 —?setDuration(long) public ObjectAnimator setDuration(long duration) { // 運行的是父類?ValueAnimator 的setDuration()方法 super.setDuration(duration); private static float sDurationScale = 1.0f; // How long the animation should last in ms 默認時間是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 的值終于是由我們調用?setDuration( )方法時傳入的?duration 乘以?sDurationScale 得出的,sDurationScale 默認值為?1.0f ; 而且 ValueAnimator 類中提供了靜態方法 setDurationScale() 供我們使用 public static void setDurationScale(float durationScale) { ? ? ? ? sDurationScale = durationScale; } 我們能夠利用這種方法改變動畫的速度

    下邊來看屬性動畫的運行過程 —— start( )方法
    從上文的分析,我們注意到,使用ObjectAnimator類的靜態方法ofFloat來創建動畫對象的過程中,ObjectAnimator類僅僅是復寫了父類ValueAnimator的一部分方法,相同也僅僅擁有部分僅僅屬于自己的成員變量,其實。我們在使用屬性動畫時。所涉及到的類的繼承關系例如以下: [java]?view plaincopy
  • /**?
  • ?*?This?is?the?superclass?for?classes?which?provide?basic?support?for?animations?which?can?be?
  • ?*?started,?ended,?and?have?<code>AnimatorListeners</code>?added?to?them.?
  • ?*/??
  • ?//這是那些為動畫提供最基礎的支持以讓動畫能被開啟、結束和被添加監聽的類的超類??
  • public?abstract?class?Animator?implements?Cloneable?{?}??
  • Animator 是屬性動畫體系的超類,它定義了諸如?start()、cancel()、end()、setDuration(long duration)、setInterpolator(TimeInterpolator value)、isRunning()、addListener(AnimatorListener listener)、removeAllListeners() 等方法 AnimatorSet 在屬性動畫中的使用方法和在補間動畫中類似,不細講了 ValueAnimator 和?ObjectAnimator 是屬性動畫的實現類,它們的差別在哪里?分析完start( ) 方法,再結合上邊的?ofFloat( ) 方法進行總結
    ObjectAnimator 的?start() 方法: [java]?view plaincopy
  • public?void?start()?{??
  • ????//?See?if?any?of?the?current?active/pending?animators?need?to?be?canceled??
  • ????AnimationHandler?handler?=?sAnimationHandler.get();??
  • ????if?(handler?!=?null)?{?...?...?}?//?第一次進入這里?handler?應該是?null??
  • ????super.start();?//?運行父類的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 Looperon 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> ? ? ?*/ ? ? ?// 開始運行動畫,這個start()?方法 有一個boolean型的參數用于標示該動畫是否須要反轉,該參數一般為false。可是也可能 ? ? // 被設置為true假設start()?方法是從?reverse()?方法中調用的,該動畫將執行在調用?start()?方法的線程里,這個線程須要擁有 ? ? ?//?一個Looper 對象,否則會發生異常 ... ... private void start(boolean playBackwards) { if (Looper.myLooper() == null) { ? ? ? ? ? ? ? throw new AndroidRuntimeException("Animators may only be run on Looper threads"); ? ? ? ? } ? ? ? ? mPlayingBackwards = playBackwards;?// 動畫是否反轉的標示 //?This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the??repeatCount //??(if repeatCount!=INFINITE), the animation ends?這個變量用于記錄當前動畫的循環次數。當mCurrentIteration?超過了 //?repeatCount(假設repeatCount 不等于 -1),動畫將被終止,該變量默認值為0 ? ? ? ? mCurrentIteration = 0;? ? ? ? ? mPlayingState = STOPPED;//標示動畫的狀態,下面是ValueAnimator中對動畫狀態的定義: /** ? ? ?* Values used with internal variable mPlayingState to indicate the current state of an?animation. ? ? ?*/ ? ???// 變量mPlayingState?使用這些值來標示動畫的狀態 ? ? static final int STOPPED ? ?= 0;?// Not yet playing 尚未開始 ? ? static final int RUNNING ? ?= 1;?// Playing normally 正常進行中 ? ? 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) {// 第一次運行,走下邊的邏輯 ? ? ? ? ? ? ? handler = new AnimationHandler(); ? ? ? ? ? ? ? sAnimationHandler.set(handler);// 此處涉及ThreadLocal的使用,暫不細說 ? ? ? ? } ? ? ? ? return handler; } // 將此動畫對象加入到AnimationHandler的mPendingAnimations集合中 animationHandler.mPendingAnimations.add(this); ? ? ? ? if (mStartDelay == 0) { ??// The amount of time in ms to delay starting the animation after start() is called 調用start()方法之后延遲多少時間播放動畫 ? ? private long mStartDelay = 0;// 默覺得零,運行下邊的邏輯 ? ? ? ? ??// 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( )方法中,須要重點分析的就是setCurrentPlayTime(0)和animationHandler.start()這兩個方法 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 復寫了父類的initAnimation()方法 void initAnimation() { ? ? ? ? if (!mInitialized) {?// 此時mInitialized的值為false,運行下邊邏輯 ? ? ? ? ? ??// 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(); ? ? ? ? } ? ? } 上邊第?步運行的是PropertyValuesHolder的setupSetterAndGetter()方法。來看詳細邏輯: [java]?view plaincopy
  • void?setupSetterAndGetter(Object?target)?{??
  • ????if?(mProperty?!=?null)?{??
  • ????????//?check?to?make?sure?that?mProperty?is?on?the?class?of?target??
  • ????????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;??
  • ????????}??
  • ????}??
  • ????//?從上文中屬性動畫的創建的分析來看,此時的mProperty?為null,從下邊開始運行??
  • ????Class?targetClass?=?target.getClass();??
  • ????if?(mSetter?==?null)?{??
  • ????????//?PropertyValuesHolder?的成員變量?Method?mSetter,默覺得null??
  • ????????setupSetter(targetClass);??
  • ????}??
  • ????for?(Keyframe?kf?:?mKeyframeSet.mKeyframes)?{??
  • ????????if?(!kf.hasValue())?{??
  • ????????????if?(mGetter?==?null)?{??
  • ????????????????setupGetter(targetClass);??
  • ????????????????if?(mGetter?==?null)?{??
  • ????????????????????//?PropertyValuesHolder?的成員變量?private?Method?mGetter,默覺得null??
  • ????????????????????//?Already?logged?the?error?-?just?return?to?avoid?NPE??
  • ????????????????????return;??
  • ????????????????}??
  • ????????????}??
  • ????????????try?{??
  • ????????????????kf.setValue(mGetter.invoke(target));??
  • ????????????}?catch?(InvocationTargetException?e)?{??
  • ????????????????Log.e("PropertyValuesHolder",?e.toString());??
  • ????????????}?catch?(IllegalAccessException?e)?{??
  • ????????????????Log.e("PropertyValuesHolder",?e.toString());??
  • ????????????}??
  • ????????}??
  • ????}??
  • }??
  • setupSetterAndGetter()方法中,重點分析setupSetter(targetClass)、setupGetter(targetClass)以及kf.setValue(mGetter.invoke(target))方法 setupSetter(targetClass)方法 [java]?view plaincopy
  • void?setupSetter(Class?targetClass)?{??
  • ????//?能夠看到,該方法的主要作用就是給PropertyValuesHolder?的成員變量?Method?mSetter?賦值??
  • ????mSetter?=?setupSetterOrGetter(targetClass,?sSetterPropertyMap,?"set",?mValueType);??
  • }??
  • setupGetter(Class targetClass)方法
    [java]?view plaincopy
  • private?void?setupGetter(Class?targetClass)?{??
  • ????//?能夠看到,該方法的主要作用就是給?PropertyValuesHolder?的成員變量?Method?mGetter?賦值??
  • ????mGetter?=?setupSetterOrGetter(targetClass,?sGetterPropertyMap,?"get",?null);??
  • }??
  • setupSetter(targetClass) 和 setupGetter(targetClass) 方法都調用了setupSetterOrGetter 方法,僅僅是參數有所不同,第一個和第三個好理解,第二個參數是一個集合,其定義例如以下:
    [java]?view plaincopy
  • //These?maps?hold?all?property?entries?for?a?particular?class.?This?map?is?used?to?speed?up?property/setter/getter?lookups?for?a?given???
  • //class/property?combination.?No?need?to?use?reflection?on?the?combination?more?than?once.?也比較簡單明了??
  • 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>>();???
  • 第四個參數。對于setupSetter()方法來講,傳入的是mValueType(我們在創建動畫對象時已為其賦值),而對于setupGetter()方法來講,傳入的是null,來看setupSetterOrGetter 方法的主要邏輯:
    [java]?view plaincopy
  • /**?
  • ?*?Returns?the?setter?or?getter?requested.?This?utility?function?checks?whether?the?requested?method?exists?in?the?propertyMapMap?
  • ?*?cache.?If?not,?it?calls?another?utility?function?to?request?the?Method?from?the?targetClass?directly.?
  • ?*/??
  • ?//?首先看凝視。檢查propertyMapMap集合是否有所請求的?setter?or?getter?方法。假設有。返回,假設沒有。通過targetClass??
  • ?//?獲得他們。將它們緩存起來并返回??
  • private?Method?setupSetterOrGetter(Class?targetClass,??
  • ????????HashMap<Class,?HashMap<String,?Method>>?propertyMapMap,??
  • ????????String?prefix,?Class?valueType)?{??
  • ????Method?setterOrGetter?=?null;?//?定義暫時變量??
  • ????try?{??
  • ????????//?Have?to?lock?property?map?prior?to?reading?it,?to?guard?against??
  • ????????//?another?thread?putting?something?in?there?after?we've?checked?it??
  • ????????//?but?before?we've?added?an?entry?to?it??
  • ????????mPropertyMapLock.writeLock().lock();??
  • ????????HashMap<String,?Method>?propertyMap?=?propertyMapMap.get(targetClass);??
  • ????????if?(propertyMap?!=?null)?{//?第一次運行。此處propertyMap?為?null??
  • ????????????setterOrGetter?=?propertyMap.get(mPropertyName);??
  • ????????}??
  • ????????if?(setterOrGetter?==?null)?{??
  • ????????????//?Determine?the?setter?or?getter?function?using?the?JavaBeans?convention?of?setFoo?or?getFoo?for?a?property???
  • ????????????//?named?'foo'.?This?function?figures?out?what?the?name?of?the?function?should?be?and?uses?reflection?to?find?the?Method???
  • ????????????//?with?that?name?on?the?target?object.利用反射獲取set和get方法??
  • ????????????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)方法大致分析完了,它完畢了對mSetter和mGetter的初始化,接下來,對KeyframeSet的成員變量ArrayList<Keyframe> mKeyframes(上文分析過,在屬性動畫的對象創建時,就以完畢對mKeyframes的初始化。mKeyframes里邊放的是依據傳入的value構造出的動畫運行過程中的幀對象)進行遍歷。詳細邏輯是: for (Keyframe kf : mKeyframeSet.mKeyframes) { ? ? ? ? ? ? if (!kf.hasValue()) {?//?hasValue()方法定義例如以下: public boolean hasValue() { ? ? ? ? return mHasValue;?//?Keyframe的成員變量。boolean mHasValue ,默認是 false // 上文我們在講動畫創建過程中依據傳入的 values 構造出?keyframes 數組中的每一項(關鍵幀對象Keyframe)時,已經講過, //?假設我們僅僅傳入了一個參數,那么這個參數將用于構建keyframes[1],走下邊的第一個構造函數 //?keyframes[0]的值則由ofFloat(0f)來構建,走下邊的第二個構造函數,即此關鍵幀對象的mHasValue為默認值false FloatKeyframe(float fraction, float value) { ? ? ? ? ? ? mFraction = fraction; ? ? ? ? ? ? mValue = value; ? ? ? ? ? ? mValueType = float.class; ? ? ? ? ? ??mHasValue = true;?// 標示一個幀對象是否已有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值的幀對象賦值 // 上文中,講到Keyframe?對象的創建時。構造函數?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 ... ... 指的就是這個地方 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()); ? ? ? ? ? ? ? ? ?} ? ? ? ? ? } }
    至此,上邊第?步運行完了,它主要是對動畫對象的成員變量PropertyValuesHolder[] mValues做更進一步的初始化,接下來運行上文中的第?步,父類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. ... ?... ? ? ?*/ ? ???// 這種方法在運行動畫的第一幀之前被調用。假設有一個不為零的startDelay值,該方法將在對應的延遲時間執后被運行 ? ? ?// 這是一個動畫最后的初始化步驟 ... ... 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。就是依據mValueType的值設置成員變量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); ? ? ? ? ?} } ? ? ? ? ? ? ? ?} ? ? ?? ? ? ?// 如今,動畫最后的初始化已經完畢,就將?mInitialized 的值設為 true 了 ? ? ? ? ? ? ? ?mInitialized = true; ? ? ? ? } }
    到如今。上文中第?步也完畢了,我們能夠看到,這一步是在做進一步的初始化,當中對set和get方法的初始化和為沒有value值得幀對象賦值的操作是在ObjectAnimator中完畢的。而對用來計算動畫的value值的TypeEvaluator的初始化則是在ValueAnimator中完畢的
    稍后再來分析上文中第?步的doAnimationFrame(currentTime)方法,因此,在ValueAnimator的start( )方法中,須要重點分析的兩個方法之中的一個setCurrentPlayTime(0)就到此為止。接著看后邊的animationHandler.start(): animationHandler.start()方法終于會導致AnimationHandler的run方法的運行(此處細節省略): [java]?view plaincopy
  • public?void?run()?{??
  • ????mAnimationScheduled?=?false;??
  • ????//?這是AnimationHandler類中的doAnimationFrame()方法??
  • ????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); ? ? ? ?// 事實上。上述代碼最基本的就是運行了一句?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類中。有下面幾個集合: [java]?view plaincopy
  • //The?per-thread?list?of?all?active?animations??
  • protected?final?ArrayList<ValueAnimator>?mAnimations?=?new?ArrayList<ValueAnimator>();??
  • //Used?in?doAnimationFrame()?to?avoid?concurrent?modifications?of?mAnimations??
  • private?final?ArrayList<ValueAnimator>?mTmpAnimations?=?new?ArrayList<ValueAnimator>();??
  • //The?per-thread?set?of?animations?to?be?started?on?the?next?animation?frame??
  • 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( )方法中,會依據動畫的屬性值的變化。用這些集合來管理動畫對象,而且在這個過程中。會調用到最核心的ValueAnimator類的doAnimationFrame()方法(第???步)當mAnimations.contains(anim)而且doAnimationFrame()方法的返回值為true時。就會運行mEndingAnims.add(anim);將動畫對象加入到mEndingAnims集合中,接著,遍歷mEndingAnims集合,運行?mEndingAnims.get(i).endAnimation(this);主要是將mAnimations、mPendingAnimations、mDelayedAnims集合中的對象清空以及改變一些標示。標示著動畫的結束。 假設doAnimationFrame()方法的返回值為false。 則在滿足條件(!mAnimations.isEmpty() || !mDelayedAnims.isEmpty())?時。運行scheduleAnimation(),即相當于調用animationHandler.start()繼續循環。


    那么doAnimationFrame()方法的邏輯是什么? 又回到了在上文中。當時我們臨時放下沒有分析的第?步中的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; } 我們看到。在每一次調用該方法時。都會依據動畫對象的一些和時間相關的屬性的值來計算fraction的值,來推斷要返回true還是false。 從代碼中。能夠看出,fraction代表的就是動畫運行過程中的每一幀在整個動畫運行過程中所處的時間的比率。


    分析到此。整個屬性動畫的實現原理基本清楚了,還剩最后一點 —— 每一次調用animationFrame方法時,怎么利用計算出來的fraction來改變動畫作用對象的屬性值以達到動畫的效果?答案是上文中?處的animateValue(fraction)方法,須要注意的是,ObjectAnimator類重寫了父類的animateValue(fraction)方法,來看詳細邏輯: void animateValue(float fraction) { ? ? ? ??super.animateValue(fraction);?// 首先調用父類的方法 ? ? ? ? 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) { ??// 此時。我們在文章的開頭提到的插值器登場了 ? ? ? ? fraction =?mInterpolator.getInterpolation(fraction); private TimeInterpolator?mInterpolator?=?sDefaultInterpolator; private static final TimeInterpolator?sDefaultInterpolator?=?new AccelerateDecelerateInterpolator(); ?// 能夠看到,假設不進行設置的話,默認的插值器就是?AccelerateDecelerateInterpolator? ??? ? ?? ? ? ? ? mCurrentFraction = fraction; ? ? ? ? int numValues = mValues.length; ? ? ? ? for (int i = 0; i < numValues; ++i) { ? ? ? ?// 細節省略了 ? ? ? ? ? ? ? ?mValues[i].calculateValue(fraction); ? ? ? ? } ? ? ? ? if (mUpdateListeners != null) { ? ? ? ? ? ? ? ?int numListeners = mUpdateListeners.size(); ? ? ? ? ? ? ? ?for (int i = 0; i < numListeners; ++i) { ? ? ? ? ? ? ? ? ? ? ?mUpdateListeners.get(i).onAnimationUpdate(this); ? ? ? ? ? ? ? ?} ? ? ? ? } }

    至此,屬性動畫實現原理基本清楚了。

    轉載于:https://www.cnblogs.com/gccbuaa/p/7295246.html

    總結

    以上是生活随笔為你收集整理的Android - Animation(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    欧美巨乳网 | 久久一级片 | 天天干夜夜想 | 激情久久伊人 | 国产剧情一区二区在线观看 | 欧美精品久久久久久久久久丰满 | 免费h精品视频在线播放 | 91视频免费观看 | 综合精品久久久 | 欧美日韩视频精品 | 免费av在线网 | 99久久久国产精品美女 | 97涩涩视频 | 日日夜夜91 | 免费在线观看成人小视频 | 欧美有色 | 少妇bbbb | 在线观看蜜桃视频 | 最新免费av在线 | av在线电影播放 | 丁香六月婷 | 欧美日韩国产在线精品 | 欧美性黄网官网 | 丁香六月在线观看 | 天天玩夜夜操 | 黄色1级毛片 | av电影中文字幕在线观看 | 亚洲一级电影在线观看 | 色五月成人 | 久久99国产视频 | 亚洲综合视频在线播放 | 欧美一级片免费在线观看 | 天天干夜夜夜操天 | 操操操综合 | 色多多视频在线 | 91视频久久久久久 | 久久五月情影视 | 一区二区亚洲精品 | 国产精品成人免费精品自在线观看 | 黄色免费网站大全 | 国产美女久久 | 中文字幕在线观看视频一区 | 涩涩伊人| 91精品人成在线观看 | 美女视频久久 | 欧美国产一区在线 | 高清日韩一区二区 | 中文字幕国语官网在线视频 | 欧美狠狠操 | 国产高清视频在线观看 | 久久久片| av黄色在线播放 | a精品视频 | 99精品视频免费全部在线 | 日韩区欠美精品av视频 | 色噜噜在线观看视频 | 911免费视频| 免费看的黄色的网站 | 久久久久成人免费 | 精品国产伦一区二区三区观看方式 | 高清一区二区三区 | 久久精品国产美女 | 色视频网址 | 99精品热视频只有精品10 | 日本久久久久久 | 婷婷视频在线播放 | 中文字幕在线观看91 | 最新中文字幕在线播放 | 免费观看成人网 | 狠狠色丁香婷婷综合欧美 | 麻豆视频在线 | 在线天堂日本 | 久久免费视频网站 | 亚洲欧美少妇 | 九九视频免费在线观看 | 午夜av在线免费 | 波多野结衣久久资源 | 国产一卡久久电影永久 | 久久午夜国产精品 | 中文字幕在线观看视频免费 | 91精品啪在线观看国产线免费 | 国产精品久久精品国产 | 亚洲国产精品电影 | 一区二区免费不卡在线 | 美女免费黄视频网站 | 久久免费99 | 91免费视频国产 | 亚洲精品小视频 | 毛片网在线观看 | 国产在线综合视频 | 中文字幕免费 | 免费观看一级特黄欧美大片 | 日韩免费av片 | 国产精品一区二区三区视频免费 | 中文字幕激情 | 婷婷激情综合 | 久久免费中文视频 | 亚洲一区二区天堂 | 香蕉视频4aa | 五月天丁香 | 黄色的片子 | 欧美日韩一区二区在线观看 | 亚洲最大av网站 | 国产一在线精品一区在线观看 | 欧美一级片免费在线观看 | 国产999免费视频 | 久草在线免费资源 | 天天添夜夜操 | 国产精品aⅴ | 国产精品久久久久久久久久久久冷 | 国内精品久久久久影院一蜜桃 | 国产成人61精品免费看片 | 91手机视频 | 色av色av色av | 五月天色中色 | 国产一区二区三区四区大秀 | 在线色吧 | 亚洲精品麻豆 | 日日日日干 | 久久人视频 | 天天干中文字幕 | 亚洲高清在线视频 | 国产99久久久精品 | 国产免费人人看 | 久草在线视频在线观看 | 国产精品18久久久久vr手机版特色 | 免费看日韩片 | 成人av网站在线 | 久久艹艹 | 久久免费a | 日韩精品一区二区在线 | 成人精品亚洲 | 成人av网站在线播放 | 超碰国产在线播放 | 久久97精品 | 18做爰免费视频网站 | 99精品影视| 国产成人亚洲在线观看 | 国产精品video | 天天干视频在线 | 欧美日韩不卡一区二区 | 国产精品美女久久久久久久久 | 亚洲永久精品在线观看 | 九九国产视频 | 婷婷激情影院 | 美女视频黄频 | 黄色三级网站在线观看 | 精品乱码一区二区三四区 | 欧美aa一级片 | 亚洲涩涩网 | 久久国产乱| 精品一区二区免费视频 | 免费在线观看不卡av | 一区二区精品在线 | 99色| 国产一级精品绿帽视频 | 国产精品乱看 | 射久久| 在线视频你懂 | 国内外成人在线视频 | 色网址99 | 日本中文字幕视频 | a黄在线观看 | 国产精品综合久久久久 | 激情综合网五月婷婷 | 一级片免费视频 | 丁香激情综合 | 综合网成人 | 91精品视频一区二区三区 | 国产精品岛国久久久久久久久红粉 | 欧美专区日韩专区 | 婷五月天激情 | 96精品在线| 黄色av影视 | 伊人永久在线 | 国产日韩三级 | 成人毛片一区二区三区 | 婷婷久操 | 人人干天天射 | 欧美久久久久久久久久 | 国产精品免费在线 | 一区二区丝袜 | 97成人精品视频在线播放 | 日韩精品无| 91香蕉国产 | 天天天干天天天操 | 久久黄色精品视频 | 免费高清看电视网站 | 午夜狠狠干| 久久免费福利 | 黄色片免费在线 | 国产精品a成v人在线播放 | av电影一区二区三区 | 欧美激情综合色综合啪啪五月 | 五月婷婷丁香色 | 精品日本视频 | 久久久穴 | 欧美日韩免费视频 | 日韩精品一区二区三区免费视频观看 | 婷婷丁香花五月天 | 日韩精品中文字幕在线播放 | 色资源二区在线视频 | 日韩高清免费观看 | 色视频网站在线 | 免费下载高清毛片 | 五月婷婷久久丁香 | 国产成人精品一区一区一区 | 天天爽夜夜爽人人爽曰av | 亚洲国产日韩一区 | 激情网站五月天 | 国产精品自产拍在线观看网站 | 国产精品九九久久久久久久 | 综合网天天色 | 亚洲成人av一区二区 | 久久久麻豆视频 | 日韩91精品 | 九九综合久久 | 一区二区免费不卡在线 | 亚洲精品五月 | 久久成人国产精品入口 | 又黄又刺激视频 | 日韩av在线看| 色综合天天狠天天透天天伊人 | 黄色影院在线免费观看 | 麻豆国产网站入口 | wwxxx日本| 日韩区视频| 亚洲精品美女在线观看 | 亚洲a色 | 丁香婷婷综合激情 | 国产又粗又硬又爽视频 | 婷婷在线网 | 在线三级播放 | 久久伊人婷婷 | 久青草视频 | 欧美在线你懂的 | 一区二区三区在线播放 | 色欧美视频 | 天天干天天草 | 国产精品午夜久久 | 国产免费久久av | 九草在线观看 | 91亚色视频| 国产91精品一区二区绿帽 | 91麻豆国产 | 国产美女精品久久久 | 免费在线一区二区 | 中文字幕一区二区三 | 久久精选| 天天色综合久久 | 五月婷婷免费 | 欧美一进一出抽搐大尺度视频 | 黄色三级免费观看 | 97超碰国产精品 | 亚洲综合欧美日韩狠狠色 | 亚在线播放中文视频 | 日韩免费av网址 | 日韩久久久久久久久久久久 | 欧美另类交人妖 | 麻豆视频在线免费观看 | 在线看一级片 | 欧美日韩久久不卡 | 五月天婷婷综合 | av不卡中文字幕 | 在线韩国电影免费观影完整版 | 亚洲欧美国产日韩在线观看 | 成人在线免费看 | 日本乱码在线 | 国产精品自在欧美一区 | 五月婷婷丁香综合 | 三级av免费看 | 亚洲国产精品推荐 | 99久久精品国产欧美主题曲 | 九九九视频在线 | 亚洲国产婷婷 | 国产精品久久久久久久电影 | 成人一级片免费看 | 精品在线免费视频 | 国产色秀视频 | 日本在线观看一区二区三区 | 最近中文字幕 | 夜夜骑日日操 | 中文字幕免费一区二区 | 中文字幕国产视频 | 欧美日韩三区二区 | 亚洲成aⅴ人在线观看 | 香蕉视频一级 | 久久精品a | 国产精品系列在线观看 | 国产原创在线视频 | 91视频a| 欧美视频二区 | 黄色网www| 欧美激情操 | 99久久精品国产一区二区成人 | 射久久久 | 99视频精品免费观看, | 亚洲国产精品女人久久久 | 免费久久片 | 久久久久久福利 | 亚洲黄色在线免费观看 | 国产精品99久久久久久武松影视 | 激情五月播播久久久精品 | 99久高清在线观看视频99精品热在线观看视频 | 免费久久久久久 | 中文在线a√在线 | 超碰在线人人97 | 深夜激情影院 | 久久久久久久久久久影院 | av久久久| 不卡的av在线播放 | 久久久久国产精品一区二区 | 美女露久久 | 一区二区三区四区五区六区 | 日韩中文免费视频 | 久久综合九色九九 | 999久久久免费精品国产 | 91成人精品| 久久99久久99精品免观看软件 | 亚洲蜜桃在线 | 亚洲免费成人av电影 | 国语黄色片| 免费国产一区二区 | 西西www4444大胆视频 | 国产精品免费视频观看 | 亚洲好视频 | 精品一区二区精品 | 麻豆视传媒官网免费观看 | 99亚洲精品 | 天天爽天天爽天天爽 | 久草在线免费在线观看 | 黄色app网站在线观看 | 四虎亚洲精品 | 日韩三级一区 | 亚洲国产精品传媒在线观看 | 在线免费日韩 | 视频在线观看一区 | 日韩精品在线看 | 丁香婷婷激情网 | 国产婷婷久久 | www.色就是色| 久久久久高清 | 久久久久久久久久久黄色 | 欧美大片mv免费 | 久久狠狠干 | 成人欧美一区二区三区黑人麻豆 | 99热这里精品 | 亚洲人人射 | 婷婷国产视频 | 成人av影视观看 | 中文免费在线观看 | 久久久久国产精品www | 日韩精品首页 | 国产精品免费成人 | 亚洲欧洲一区二区在线观看 | 中文字幕视频 | 国产精品久久一区二区三区, | 亚洲第一伊人 | 亚洲视频网站在线观看 | 日韩国产精品毛片 | 国产精品久久久久久久久久妇女 | 香蕉视频在线免费 | 日本中文字幕网 | 日日爽日日操 | 亚洲精品久久久久久中文传媒 | 亚洲午夜精品久久久 | 国产手机在线观看视频 | 中文字幕中文字幕 | 国产精品国产亚洲精品看不卡15 | 国产精品一区久久久久 | 亚洲国产成人在线观看 | 国产精品福利久久久 | 黄色免费网站下载 | 国产精品久久久99 | 欧美伦理一区二区三区 | 九九视频在线播放 | 97精品国产91久久久久久 | 91视频 - x99av | 亚洲成人av在线 | 国产精品久久久久一区二区三区共 | 超碰在线99 | 亚洲国产黄色片 | 天天干天天操 | 久久99精品国产 | 欧美精品乱码99久久影院 | 亚洲动漫在线观看 | 香蕉视频18| 99电影| va视频在线 | 欧美一区二区三区免费看 | 成年人电影免费在线观看 | 久久综合五月天婷婷伊人 | 黄色影院在线免费观看 | 国产涩涩网站 | ,午夜性刺激免费看视频 | 婷婷色婷婷 | 插久久 | 人人爽人人片 | 97国产大学生情侣酒店的特点 | 精品高清美女精品国产区 | 日韩高清不卡在线 | 午夜精品一区二区三区在线 | av在线观 | av大全在线观看 | 国产男女无遮挡猛进猛出在线观看 | 在线观看aaa | 色噜噜日韩精品一区二区三区视频 | 中文字幕电影一区 | 91九色视频网站 | 国产精品久久久久久久免费大片 | 日韩大片在线看 | 亚洲二区精品 | 99免费精品视频 | 一级黄色毛片 | 国产精品一区二区中文字幕 | 久久视奸| 中文字幕一区在线 | 成在人线av| 操久久网 | 亚州精品一二三区 | 韩国av免费观看 | 500部大龄熟乱视频 欧美日本三级 | 西西www4444大胆在线 | 日韩欧美在线中文字幕 | 色综合天天天天做夜夜夜夜做 | 欧美精品二区 | 成人免费看电影 | 在线看91| 久久久久久久久久久影视 | 久久人人爽人人片 | 久久久精品免费观看 | av在线电影网站 | 狠狠操电影网 | 亚洲尺码电影av久久 | 五月婷婷在线视频 | 色先锋资源网 | www.色在线| 玖草影院| 手机在线看a | 超碰97在线资源 | 中文字幕在线观看完整版电影 | 国产精品免费在线观看视频 | 综合铜03 | 97超碰人人模人人人爽人人爱 | 国产无遮挡又黄又爽馒头漫画 | 中文字幕色综合网 | 亚洲狠狠婷婷综合久久久 | 国产精品专区在线 | 国产视频久久久 | 国产日韩欧美视频在线观看 | 欧美一级免费高清 | 91黄色视屏 | 日本中文在线观看 | 国产精品黄色 | 国产精品久久久久影视 | 九九av | 欧美一级黄大片 | 黄色精品一区 | а中文在线天堂 | av网站手机在线观看 | 久久亚洲电影 | 在线成人观看 | 久久视频国产精品免费视频在线 | 久久久久区 | 婷婷夜夜 | 国产成人av在线影院 | 人人精久 | 日韩专区av| 久久综合九色综合欧美狠狠 | 婷婷5月色 | 最近中文字幕高清字幕免费mv | 日韩区在线观看 | 天天干天天干天天干 | 999久久国精品免费观看网站 | 亚洲永久免费av | 久久天天操 | 欧美视频网址 | 久久久99精品免费观看乱色 | 视频在线91| 美女久久久久久久久久久 | 国内精品久久久久久久 | 欧美一级高清片 | 最近高清中文字幕在线国语5 | 又湿又紧又大又爽a视频国产 | 伊人影院在线观看 | 精品av网站 | 免费视频一级片 | 亚洲国产精品999 | 国产精品久久一区二区三区不卡 | 中文字幕国产视频 | 麻花豆传媒mv在线观看网站 | 久久国产美女 | 久9在线 | 又污又黄网站 | 91在线操 | 97超碰超碰久久福利超碰 | 中文字幕资源站 | 深夜福利视频一区二区 | 青草视频在线看 | 日韩欧美视频一区二区三区 | 国产小视频91 | 亚洲精品美女久久久 | 一级免费片| 日韩色一区二区三区 | 天天摸天天舔 | 97超级碰 | 麻豆久久| 国产大片免费久久 | 婷婷伊人网 | 亚洲综合射 | 亚洲国产三级在线观看 | 91| 久草在线免费在线观看 | 日日日视频 | 伊人精品在线 | 色婷婷成人网 | av免费看看| 日韩免费一区二区三区 | 精品国产一区二区三区四区vr | 在线观看精品一区 | 国产视频在线观看一区二区 | 久久人人爽爽人人爽人人片av | 成年人电影毛片 | 色综合久 | 欧美一二三区在线观看 | 五月婷社区 | 亚洲午夜精品久久久 | 婷婷激情欧美 | 国产一区私人高清影院 | 手机av在线免费观看 | 久久夜色精品国产亚洲aⅴ 91chinesexxx | 中文字幕日本在线观看 | 九九热免费精品视频 | 欧美了一区在线观看 | 日本色小说视频 | 免费在线观看成人小视频 | 五月天激情视频在线观看 | www欧美色 | 日本黄色免费在线 | 91视频 - v11av | av福利在线播放 | 日韩中文在线播放 | 日韩av手机在线看 | a成人v在线| 最近中文字幕高清字幕在线视频 | 欧美日韩在线免费观看视频 | 免费在线观看国产黄 | 91av在线免费视频 | 成人av日韩 | 亚洲美女视频在线观看 | 在线观看理论 | 少妇精品久久久一区二区免费 | 日女人免费视频 | 国产精品一区一区三区 | 97av超碰| 亚洲网站在线 | 婷婷色综合 | 中文字幕免费久久 | 国内久久视频 | 午夜美女wwww | 高清视频一区二区三区 | 极品嫩模被强到高潮呻吟91 | 欧美日韩精品二区第二页 | 蜜臀av性久久久久蜜臀aⅴ四虎 | 在线免费成人 | 日本狠狠色 | 婷婷色视频 | 黄色毛片网站在线观看 | 国产精品九九视频 | 在线观看视频国产 | 国产精品一区二区三区四 | 免费情缘 | 久99久精品 | 日韩影视在线观看 | 91九色在线| 亚洲精品影视在线观看 | 久久99久久99精品中文字幕 | 永久黄网站色视频免费观看w | 日韩在线不卡视频 | 97在线视频免费播放 | 国产成人精品一区二区三区 | 中文字幕视频一区二区 | 欧美精品天堂 | 亚洲国产97在线精品一区 | 国产操在线 | 国产午夜精品理论片在线 | 国产精品区在线观看 | 日韩高清一区二区 | 日韩免费专区 | 911久久 | 一区二区三区精品在线视频 | 岛国大片免费视频 | 欧美成年黄网站色视频 | 免费精品在线观看 | 亚洲一区二区三区91 | 久久精品综合 | 国产 亚洲 欧美 在线 | 亚洲国产精品资源 | 久青草电影| av超碰在线| 亚洲欧洲精品久久 | 天天色成人网 | 日韩一区在线免费观看 | 99久久这里有精品 | 日韩综合一区二区三区 | 国产最新视频在线 | 国产精品一区二区久久国产 | 天天干天天做天天操 | 亚洲成色777777在线观看影院 | 日本中文字幕系列 | 麻豆视频国产在线观看 | 亚洲精品国产第一综合99久久 | 超碰激情在线 | www黄色av | 久99久在线 | 日韩精品一区二区三区在线视频 | 国产精品18久久久久久久网站 | 91探花系列在线播放 | 国产精品破处视频 | 亚洲首页| 黄色网大全| 99在线观看精品 | 亚洲国产精品电影 | 五月天久久婷 | 欧美性视频网站 | 欧美福利视频 | 91精品久久香蕉国产线看观看 | 91色视频 | 最新真实国产在线视频 | 免费激情在线电影 | 日本高清中文字幕有码在线 | 97免费在线观看 | 国产 日韩 欧美 自拍 | 国产精品一区二区三区在线免费观看 | 不卡电影一区二区三区 | 日韩免费观看一区二区三区 | 亚洲精品视频免费在线观看 | 精品一区电影国产 | 日本中文字幕免费观看 | 精品久久影院 | 国产美女搞久久 | 一区二区不卡 | www.色婷婷.com | 亚洲五月六月 | 精品国产欧美一区二区三区不卡 | 天天操天天操一操 | 日韩国产欧美在线视频 | 91色偷偷 | 97在线精品 | 97精品国产| 国产精品一区二区电影 | 天天插天天狠 | 国产中文字幕视频在线观看 | 久久久久久国产精品亚洲78 | 亚洲另类视频在线 | 精品久久久久免费极品大片 | av电影不卡 | 午夜三级毛片 | 日日天天 | 亚洲欧美日韩国产一区二区三区 | 高潮久久久久久 | 狠狠色丁香久久婷婷综合五月 | 欧美日韩二三区 | 国产69精品久久久久久久久久 | 美女国产 | 少妇bbw搡bbbb搡bbbb | 韩国av一区二区三区在线观看 | 日本xxxx.com| 午夜精品久久久久久久99无限制 | 精品一区二区电影 | 青青河边草手机免费 | 亚洲成年人av | 国产精品久久久久久久久免费看 | 日韩精品专区 | 成人国产一区二区 | 国产精品久久久久久婷婷天堂 | 欧美成人手机版 | 国产成人免费观看 | 亚洲国产丝袜在线观看 | 国产99久久久久 | 天天色成人网 | 国产精品xxxx18a99| 成年人黄色免费视频 | 超碰人人做| 成年人网站免费在线观看 | 国产在线观看黄 | 久久久久久久久综合 | 亚洲精品在线视频网站 | 亚洲天堂社区 | 人人玩人人添人人澡超碰 | 欧亚久久| 少妇超碰在线 | 91九色porny在线 | 日本精品久久久久中文字幕 | 最近中文字幕视频网 | 久久久久久久久久电影 | 精品久久久精品 | 91片在线观看 | 在线播放国产一区二区三区 | 国产一区二区视频在线 | 五月婷婷中文网 | 波多野结衣在线观看一区二区三区 | 成 人 黄 色 视频免费播放 | 亚洲精品乱码久久久久久蜜桃动漫 | wwwwwww色| 久要激情网| 婷婷中文字幕综合 | 91超碰免费在线 | 色狠狠操 | 亚洲劲爆av | 国产美女精品视频 | 亚洲精品在线观看免费 | 国产一级性生活 | 玖玖精品视频 | 中文字幕在线免费播放 | 男女拍拍免费视频 | 国产免费作爱视频 | 丁香在线观看完整电影视频 | 免费看久久久 | 欧美激情亚洲综合 | 日韩久久精品一区二区 | 欧美精品一区在线发布 | 激情综合网婷婷 | 欧美成人手机版 | www.天天干| 欧美成人免费在线 | 性色av一区二区三区在线观看 | 中文字幕一区二区三区乱码在线 | 九九久久精品 | 天天艹天天 | 人人插人人看 | 亚洲天堂社区 | 97视频在线免费播放 | 国产一区在线视频观看 | 在线观看色视频 | 久久久久久久久久久综合 | 中文字幕丝袜制服 | 久久综合九色综合欧美就去吻 | 国产精品不卡一区 | av在线免费在线观看 | 天天干天天操天天搞 | www免费| 国产在线一线 | 亚洲色综合 | 91精品久久久久久久久久入口 | 色就干| 久久久亚洲成人 | 日韩乱码中文字幕 | 亚洲精品2区 | 99久久99热这里只有精品 | 午夜久久久久久久久久影院 | 国产精品字幕 | 欧美视频在线观看免费网址 | 一区二区三区播放 | 国产日韩欧美视频 | 在线观看一区二区视频 | 日韩午夜三级 | 一色av | 狠狠艹夜夜干 | 玖玖在线视频观看 | 午夜国产成人 | 午夜久久精品 | 国产精品久久久视频 | 青青草在久久免费久久免费 | 精品一区电影国产 | 欧美激情精品久久久久久变态 | 天天干夜夜 | 免费观看性生交 | 免费aa大片 | 国产黄色电影 | 国产明星视频三级a三级点| 天天综合网天天综合色 | 欧美巨大荫蒂茸毛毛人妖 | 国产91精品欧美 | 亚洲精品一区二区网址 | 色婷婷综合久久久 | 91精品国产麻豆 | 国产精品99精品 | 999久久国产 | 久草视频在线看 | 中文字幕国语官网在线视频 | 久久少妇av| 91久久久国产精品 | 免费高清男女打扑克视频 | 99久久日韩精品视频免费在线观看 | 免费av影视 | 日本久久99| 国产97色在线 | av午夜电影 | 久久99久久精品 | 国产成人99av超碰超爽 | 午夜婷婷网 | 国产1级视频 | 国产一区福利在线 | 十八岁免进欧美 | 黄色视屏在线免费观看 | 蜜臀aⅴ精品一区二区三区 久久视屏网 | 亚洲国产成人精品久久 | 欧美午夜精品久久久久久浪潮 | 国产va精品免费观看 | 国产乱老熟视频网88av | 亚洲毛片一区二区三区 | 亚洲一级黄色片 | 免费三级av | 亚洲精品乱码久久久久久高潮 | 成片人卡1卡2卡3手机免费看 | 在线国产中文字幕 | 国产在线观看99 | 毛片基地黄久久久久久天堂 | 国产不卡网站 | 日韩爱爱网站 | 激情av资源| 日日躁你夜夜躁你av蜜 | 高清国产在线一区 | 久久久精华网 | 日日激情| 日韩在线一区二区免费 | 性色av免费看 | 在线视频成人 | 91精品在线观看入口 | 五月婷婷激情综合 | 久久经典国产视频 | avwww在线 | 日韩 在线 | 久久成人精品电影 | 在线观看mv的中文字幕网站 | 久久艹在线观看 | 中文字幕之中文字幕 | 国产精品一区二区三区四 | 91天堂素人约啪 | av在线进入 | 中文字幕精品三区 | 欧美成人精品欧美一级乱 | 91福利小视频 | 最新一区二区三区 | 91九色国产在线 | 黄视频色网站 | 亚洲精品在线一区二区 | 日日日日 | 99精品视频免费观看视频 | 香蕉网在线播放 | 久草观看 | 成人免费在线视频观看 | 久久一区二区三区日韩 | 中文字幕在线视频精品 | 在线免费观看国产精品 | 色网站免费在线观看 | 超碰97在线看 | 国产精品成 | 国产精品午夜8888 | 久久久免费看片 | 久久综合九色综合久久久精品综合 | 国产精品久久久久久妇 | 久草视频在线免费看 | 97超碰在线免费观看 | 国产精品久久一区二区无卡 | 四虎国产精品成人免费影视 | 久久手机视频 | 91精品一区二区在线观看 | 国产精品久久久久久久久久久久久 | 一区二区三区国产精品 | wwwwww黄| 久久爱影视i | 狠狠狠狠狠狠操 | 国产日韩精品视频 | 免费在线h| 麻豆果冻剧传媒在线播放 | 国产精品久久99综合免费观看尤物 | 欧美片网站yy | 婷婷六月天丁香 | 成人午夜网址 | 婷婷免费在线视频 | 久章草在线观看 | 久久久久久久久久久精 | 五月综合色 | 亚洲成人中文在线 | 亚洲午夜av| 粉嫩aⅴ一区二区三区 | 毛片久久久 | 久久久私人影院 | 亚洲成人黄色av | 亚洲永久精品一区 | 亚洲日日夜夜 | 91成人在线观看喷潮 | 国产美女在线精品免费观看 | 天天射天天干天天操 | 亚洲精品视频www | 日韩av电影中文字幕在线观看 | 在线精品一区二区 | 91丨九色丨勾搭 | 日本福利视频在线 | 99精品国产福利在线观看免费 | 99精品视频免费 | 91在线观看高清 | 国产一区二区视频在线播放 | 97在线观看视频 | 美女网站在线播放 | 日韩精品三区四区 | 成年美女黄网站色大片免费看 | 色视频在线观看 | 最新免费中文字幕 | 天天射天天干天天操 | 精品视频免费看 | 日韩影视精品 | 久久久久 免费视频 | 波多野结衣在线视频免费观看 | 婷婷丁香色 | www.久久久.com| 日韩美女免费线视频 | 欧美一区二区三区在线 | 波多野结衣视频一区二区 | 亚洲视频精品 | 日日日操 | 亚洲人在线视频 | 国产第一页在线观看 | 日韩美女免费线视频 | 久久久国产精品视频 | 久久免费视频网 | a久久久久 | 亚洲欧美成人在线 | 精品久久久一区二区 | 这里有精品在线视频 | 手机看片99 | 国产精品一区在线观看你懂的 | 手机成人在线 | 91在线视频网址 | 一区二区三区免费看 | 18岁免费看片 | www.777奇米| 视频一区二区在线 | 国产精品一区二区在线播放 | 99久久婷婷国产综合亚洲 | 婷婷丁香花五月天 | 国产精品 国内视频 | 国产精品久久久久久久7电影 | 久久精品久久精品 | 日韩久久一区 | 69国产精品成人在线播放 | 国产一区国产二区在线观看 | 91精品视频免费 | 日韩在线短视频 | 欧美a级免费视频 | 999久久久久久久久6666 | 久久久综合香蕉尹人综合网 | 免费三级黄色片 | 亚洲免费av观看 | 国产黄在线播放 | 一区二区三区电影 | 国产亚洲精品久久19p | 99精品久久久久久久 | 欧美午夜性| 蜜臀av.com| 久久99视频免费 | 毛片播放网站 | 97av在线视频 | 久草在线免费资源 | 99色网站| 久久精品首页 | 中文字幕一区二区三区四区视频 | 婷婷在线视频观看 | 精品国产一二三四区 | 天堂入口网站 | 婷婷av网 | 欧日韩在线 | 永久免费精品视频网站 | 亚洲成人精品在线观看 | 日本精品久久久久久 | 亚洲aⅴ乱码精品成人区 | www视频在线观看 | 日韩激情久久 | 国产精品一区二区久久精品爱微奶 | 亚洲免费婷婷 | 精品国产中文字幕 | 91人人爽人人爽人人精88v | 97福利 | 久久久久久综合 | 91视频专区 | 久久av不卡| 中文在线www | 五月天色丁香 | 国产亚洲片 | 国产精品涩涩屋www在线观看 | 国产色拍 | 国产人成看黄久久久久久久久 | 精品亚洲在线 | 美州a亚洲一视本频v色道 | 免费观看性生交大片3 | 97理论电影 | 一区二区三区动漫 | av一级一片 | 中文字幕在线成人 | 精品福利国产 | 亚洲综合网站在线观看 | 波多野结衣精品 | 一区二区伦理电影 | 一区二区三区在线免费观看 | 亚洲精品国产精品国自产观看 | 国产日韩欧美在线一区 |