Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 屬性動畫 源碼解析 深入了解其內部實現

Android 屬性動畫 源碼解析 深入了解其內部實現

編輯:關於Android編程

 

1、概述

Android中想做很炫酷的動畫效果,相信在很多時候你都可以選擇使用屬性動畫,關於屬性動畫如何使用,我們已經很詳細的寫過兩篇博客講解。如果你還不了解,請參考:

Android 屬性動畫(Property Animation) 完全解析 (上)

Android 屬性動畫(Property Animation) 完全解析 (下)

本篇博客將分析屬性動畫的實現源碼,帶你深入的了解Android屬性動畫的內部實現機制。如果你經常用屬性動畫,但又一直沒有去查看其源碼實現,沒關系,請往下看。

2、分析前的猜想

在源碼分析之前,我們需要有一個明確的思路,例如:源碼的入口的選擇、甚至對其實現進行簡單的猜測,源碼分析相當於一個驗證的過程,帶著一個目標去看源碼,這樣的話,分析和理解起來更為方便。

對於實現屬性動畫,最常用的類就是ObjectAnimator了,只需要簡單的設置目標view,屬性,以及目標值等必要屬性,調用一下start();我們的動畫就完成了。

類似如下代碼:

 

ObjectAnimator
  .ofInt(target,propName,values[])
  .setInterpolator(LinearInterpolator)
  .setEvaluator(IntEvaluator)
  .setDuration(500)
  .start();

上述代碼很好理解吧,設置動畫作用的view,作用的屬性,動畫開始、結束、以及中間的任意個屬性值;

 

然後是設置插值器,當然了插值器這個詞比較難理解,我要是說例如:AccelerateInterpolator、LinearInterpolator

然後設置估值算法,這個看名字挺高端,其實內部實現尤其簡單: return (int)(startInt + fraction * (endValue - startInt)); 開始值,加上當前的屬性改變的百分比*(結束-開始)

當然了,這個百分比是fraction ,其實就是上面的插值器算出來的。比如線性插值器:fraction 值就是currentTime - mStartTime) / mDuration,動畫的運行時間/總設置時間。

然後是設置動畫事件,

最後start()。

好了,現在我想問個問題,根據上面這些參數,如果我要你設計個屬性動畫框架,你怎麼做?

這個嘛,好整,拿到上述參數之後,start()中,開啟一個定時器,去執行一個任務;在任務內部,根據Interpolator計算出來的fraction,交給Evaluator,得到屬性當前應該設置的值,然後反射設置tagert的指定屬性,ok,奏事這麼簡單。嗯,大體上應該就是這樣,當然了,源碼的實現肯定復雜很多,但是萬變不離其宗,所以接下來的源碼閱讀,就是去驗證我們的這個答案。

3、源碼分析

好了,猜想完了,我們就得進入驗證階段了~~

那麼,我們源碼的入口就是上述代碼了,不過貌似上述代碼調用了好幾個方法,but,我覺得start之前的代碼,無法是初始化實例,設置一些成員變量。

首先我們看ofInt,這裡為了簡單,我們的ofInt中的values參數,默認就一個,類似 .ofInt(view, translationX, 300) ;

1、ofInt

 

public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
        anim.setIntValues(values);
        return anim;
    }

 

首先調用ObjectAnimator的構造方法傳入了一個target和propName,估計就是創建對象,然後舊路下target和propName,簡單看下

 

 private ObjectAnimator(Object target, String propertyName) {
        mTarget = target;
        setPropertyName(propertyName);
    }
 public void setPropertyName(String propertyName) {
       //...
        mPropertyName = propertyName;
       mInitialized = false;
    }

記錄完成target,propName以後,調用setIntValues

 

 

@Override
    public void setIntValues(int... values) {
            setValues(PropertyValuesHolder.ofInt(mPropertyName, values));  
    }

可以看到,把我們的propName,和values傳入到了一個PropertyValuesHolder的ofInt方法中,去構造一個PropertyValuesHolder對象,這個對象是干什麼的呢?

 

從字面上看,是保存view在動畫期間的屬性和值,記住是動畫期間的。繼續往下看:

 

public static PropertyValuesHolder ofInt(String propertyName, int... values) {
        return new IntPropertyValuesHolder(propertyName, values);
    }
  public IntPropertyValuesHolder(String propertyName, int... values) {
            mPropertyName = propertyName;
            setIntValues(values);
        }
@Override
        public void setIntValues(int... values) {
            mValueType = int.class;
            mKeyframeSet = KeyframeSet.ofInt(values);
            mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
        }

可以看到在IntPropertyValuesHolder內部存儲了我們的propertyName;,然後又調用了setIntValues,存儲了我們的mValueType ,此外還存了一個mIntKeyframeSet。

 

這裡又出現一個新名詞,叫做mKeyframeSet,這個是由 KeyframeSet.ofInt(values);得到的。

那麼這個KeyframeSet是什麼呢?單純的理解是,Keyframe的集合,而Keyframe叫做關鍵幀,為一個動畫保存time/value(時間與值)對。

那麼我們去看看它是如何通過KeyframeSet.ofInt(values);去構造與保存的:

 

public static KeyframeSet ofInt(int... values) {
        int numKeyframes = values.length;
        IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
        if (numKeyframes == 1) {
            keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);
            keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);
        } else {
            //...
        }
        return new IntKeyframeSet(keyframes);
    }
 public IntKeyframeSet(IntKeyframe... keyframes) {
        mNumKeyframes = keyframes.length;
        mKeyframes = new ArrayList();
        mKeyframes.addAll(Arrays.asList(keyframes));
        mFirstKeyframe = mKeyframes.get(0);
        mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
        mInterpolator = mLastKeyframe.getInterpolator();
    }

這裡代碼跳躍比較大,部分代碼我來解釋:

 

根據我們的values的長度,構造了keyframes數組,然後分別通過Keyframe的ofInt方法,去構造keyframe對象,其實在內部:

 

IntKeyframe(float fraction, int value) {
            mFraction = fraction;
            mValue = value;
            mValueType = int.class;
            mHasValue = true;
        }

        IntKeyframe(float fraction) {
            mFraction = fraction;
            mValueType = int.class;
        }

就簡單存了一下fraction,和value;當然了,我們這裡values只有一個值,所以構造了兩個Keyframe。

 

拿到初始化完成的keyframes數組以後,將其傳入了KeyframeSet的構造方法,初始化了KeyframeSet內部的一些成員變量。

 

public IntKeyframeSet(IntKeyframe... keyframes) {
        mNumKeyframes = keyframes.length;
        mKeyframes = new ArrayList();
        mKeyframes.addAll(Arrays.asList(keyframes));
        mFirstKeyframe = mKeyframes.get(0);
        mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
        mInterpolator = mLastKeyframe.getInterpolator();
    }

存了有多少關鍵幀,開始幀,結束幀,以及插值器。

 

到此,我們的(PropertyValuesHolder.ofInt在徹底返回,可以看到這個過程中,我們成功的為PropertyValuesHolder對象賦值了propName,valueType,keyframeSet .

keyframeset中存了Keyframe集合,keyframe中存儲了(fraction , valuetype , value , hasValue)。

最後,叫 PropertyValuesHolder 交給我們的 ObjectAnimator的setValues方法。

 

 public void setValues(PropertyValuesHolder... values) {
        int numValues = values.length;
        mValues = values;
        mValuesMap = new HashMap(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;
    }
首先記錄了mValues,注意這裡的values是PropertyValuesHolder類型的,然後通過一個mValueMap記錄:key為屬性的名稱,值為PropertyValuesHolder 。

 

好了,到此我們的ofInt結束了,暈否,其實還好。如果你暈了,我幫你總結下:ofInt就是記錄了target,propName,values(是將我們傳入的int型values,輾轉轉化成了PropertyValuesHolder),以及一個mValueMap,這個map的key是propName,value是PropertyValuesHolder,在PropertyValuesHolder內部又存儲了proprName, valueType , keyframeSet等等。

好了,接下來會輕松點,按照順序到setInterpolator了:

2、setInterpolator

 

 @Override
    public void setInterpolator(TimeInterpolator value) {
        if (value != null) {
            mInterpolator = value;
        } else {
            mInterpolator = new LinearInterpolator();
        }
    }

沒撒說的,記錄下插值器,我們這裡也線性插值器,默認也是~~

 

然後是setEvaluator。

3、setEvaluator

 

 public void setEvaluator(TypeEvaluator value) {
        if (value != null && mValues != null && mValues.length > 0) {
            mValues[0].setEvaluator(value);
        }
    }

記得我們這裡的mValue吧,在ofInt裡面初始化的,類型是PropertyValuesHolder。然後調用了PropertyValuesHolder.setEvalutor

 

 

  public void setEvaluator(TypeEvaluator evaluator) {
        mEvaluator = evaluator;
        mKeyframeSet.setEvaluator(evaluator);
    }

記錄了一下估值算法,然後再將其傳給KeyframeSet對象:

 

 

public void setEvaluator(TypeEvaluator evaluator) {
        mEvaluator = evaluator;
    }

可以看到,我們把估值算法,交給了PropertyValuesHolder以及KeyframeSet。

 

接下來,最後一個屬性,duration

4、setDuration

 

 // How long the animation should last in ms
    private long mDuration = (long)(300 * sDurationScale);
    private long mUnscaledDuration = 300;
    private static float sDurationScale = 1.0f;

    public ObjectAnimator setDuration(long duration) {
        if (duration < 0) {
            throw new IllegalArgumentException(Animators cannot have negative duration:  +
                    duration);
        }
        mUnscaledDuration = duration;
        mDuration = (long)(duration * sDurationScale);
        return this;
    }

就是簡單在mDuration中記錄了一下動畫的持續時間,這個sDurationScale默認為1,貌似是用於調整,觀察動畫的,比如你可以調整為10,動畫就會慢10倍的播放。

好了,到此該設置的設置完成了,小小總結一下:

ofInt中實例化了一個ObjectAnimator對象,然後設置了target,propName,values(PropertyValuesHolder) ;然後分別在setInterpolator,setDuration設置了Interpolator和duration。其中setEvaluator是給values[0],以及keyframeSet設置估值算法。

PropertyValueHolder實際上是IntPropertyValueHolder類型對象,包含propName,valueType,keyframeSet .

keyframeset中存了Keyframe集合,keyframe中存儲了(fraction , valuetype , value , hasValue)。

以上都比較簡單,關鍵就是看start()方法中,如何將這些屬性進行合理的處理調用神馬的。

5、start

喝杯水,小憩一下,准備征戰start()方法。

 

@Override
    public void start() {
        super.start();
    }
ValueAnimator
@Override
    public void start() {
        start(false);
    }
ValueAnimator
private void start(boolean playBackwards) {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException(Animators may only be run on Looper threads);
        }
        mPlayingBackwards = playBackwards;
        mCurrentIteration = 0;
        mPlayingState = STOPPED;
        mStarted = true;
        mStartedDelay = false;
        mPaused = false;
        AnimationHandler animationHandler = getOrCreateAnimationHandler();
        animationHandler.mPendingAnimations.add(this);
        if (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的statr(playBackwards)方法;

 

15-20行:設置了關於動畫的一些標志位,mPlayingBackwards 表示動畫是否reverse;mCurrentIteration 記錄當前的動畫的執行次數(與setRepeatCount有關);mPlayingState 動畫的狀態為STOPPED;還有些其他的標志位;

21行:生成一個AnimationHandler對象,getOrCreateAnimationHandler就是在當前線程變量ThreadLocal中取出來,沒有的話,則創建一個,然後set進去。

AnimationHandler中包含一些List集合用於存儲各種狀態的ValueAnimator。

22行:將當前ValueAnimator對象,加入 animationHandler.mPendingAnimations 集合。

23行:未設置mStartDelay,默認為0,則進入循環;

24行: setCurrentPlayTime(0);一會需要細說

25-26行:設置些狀態。

27行:回調監聽動畫的接口AnimatorListener的onAnimationStart方法,如果你設置了回調監聽,此時就會進行回調;

最後30行:調用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);
    }

 

首先初始化動畫,然後得到當前的系統開始到現在的時間currentTime;設置mSeekTime,設置當前狀態為SEEKED;然後使用mSeekTime-playTime得到動畫現在需要執行的時間;最後調用 doAnimationFrame(currentTime),稍後看其代碼;

關於initAnimation(),實際就是去設置我們ValueAnimator中存儲的mValues,也就是IntPropertyValueHolder的mEvaluator;

 void initAnimation() {
        if (!mInitialized) {
            int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                mValues[i].init();
            }
            mInitialized = true;
        }

PropertyValuesHolder的init方法:

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);
        }
    }
其實就是遍歷設置PropertyValuesHolder中的mEvaluator屬性,默認根據valueType進行判斷,IntEvaluator或者FloatEvaluator。

 

接下來應該看doAnimationFrame(currentTime);了

 

 final boolean doAnimationFrame(long frameTime) {
        
        final long currentTime = Math.max(frameTime, mStartTime);
        return animationFrame(currentTime);
    }

內部調用了:animationFrame(currentTime);

 

 

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 (mPlayingBackwards) {
                fraction = 1f - fraction;
            }
            animateValue(fraction);
            break;
        }

        return done;
    }

這裡通過判斷當前動畫的狀態,給出fraction,默認傳入的就是(float)(currentTime - mStartTime) / mDuration,動畫執行的時間除以總的時間比值;

 

接下來調用了animateValue(fraction)

在animateValue的內部,會將傳入的fraction,交給 mInterpolator.getInterpolation(fraction);方法,獲得插值器處理後的fraction;然後在將fraction交給估值算法mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();進行計算得到當前時間點,屬性應該的值;最後會反射對我們設置的屬性進行設置。

終於看到,對我們的屬性的值進行設置了,偶也~~當然了,動畫如果沒結束,應該每隔一定的幀數,再次調用,嗯,的確是這樣的,你看到animationFrame最後是不是有個返回值,這個值會在fraction>=1的時候返回true;

我們還是先看看animateValue方法:

 

  void animateValue(float fraction) {
        fraction = mInterpolator.getInterpolation(fraction);
        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);
            }
        }

       int numValues = mValues.length;
        for (int i = 0; i < numValues; ++i) {
            mValues[i].setAnimatedValue(mTarget);
        }
    }

 

首先將fraction交給給 mInterpolator.getInterpolation(fraction);得到計算後的fraction;

然後for循環遍歷調用IntPropertyValueHolder的calculateValue方法:

 

  void calculateValue(float fraction) {
        mAnimatedValue = mKeyframeSet.getValue(fraction);
    }

在其內部,調用了mKeyframeSet的getValue,這裡注意我們的IntKeyFrameSet,千萬不要看錯方法了。

 

 

 @Override
    public Object getValue(float fraction) {
        return getIntValue(fraction);
    }
public int getIntValue(float fraction) {
        if (mNumKeyframes == 2) {
            if (firstTime) {
                firstTime = false;
                firstValue = ((IntKeyframe) mKeyframes.get(0)).getIntValue();
                lastValue = ((IntKeyframe) mKeyframes.get(1)).getIntValue();
                deltaValue = lastValue - firstValue;
            }
            if (mInterpolator != null) {
                fraction = mInterpolator.getInterpolation(fraction);
            }
            if (mEvaluator == null) {
                return firstValue + (int)(fraction * deltaValue);
            } else {
                return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();
            }
        }
        //...省略了很多代碼
    }

在其內部,因為我們只設置了一個目標屬性值,所以只有兩個關鍵幀;

 

然後16-20行,調用估值算法的mEvaluator.evaluate方法,可以看到如果mEvaluator == null直接調用了firstValue + (int)(fraction * deltaValue);其實這個就是IntEvaluator的默認實現。

好了,for循環結束了,經過我們插值器和估值算法得出的值,最終給了IntPropertyValueHolder的mIntAnimatedValue屬性;

回到animateValue方法:在animateValue的8-12行,繼續回調動畫監聽onAnimationUpdate(this);方法;

animateValue的15-18行:循環拿到(其實我們就只有一個屬性)我們的IntPropertyValueHolder調用setAnimatedValue,進行反射為我們的屬性設置值,反射需要一些東西,比如target,propname,以及該屬性應該設置的值;這三個參數在哪呢?target作為參數傳入了,propName初始化的時候就設置了,至於該屬性應該設置的值,上面有一句:“ 好了,for循環結束了,經過我們插值器和估值算法得出的值,最終給了IntPropertyValueHolder的mIntAnimatedValue屬性 ” 。是不是全了~~反射的代碼就不貼了。

好了,到此,我們屬性動畫,設置的各種值,經過重重的計算作用到了我們的屬性上,反射修改了我們的屬性。到此我們已經完成了一大半,但是貌似還少了個,每隔多少幀調用一次~~

嗯,的確是的,跨度好大,現在回到我們的start方法,最後一行:調用animationHandler.start();這個還沒細說呢~~

animationHandler我們上面已經介紹了,存儲在當前線程的ThreadLocal裡面,裡面放了一些集合用於存儲各種狀態的ObjectAnimator,我們當前的ObjectAnimator對象也存儲在其mPendingAnimations的集合中(上面提到過~~)。

 

/**
         * Start animating on the next frame.
         */
        public void start() {
            scheduleAnimation();
        }
private void scheduleAnimation() {
            if (!mAnimationScheduled) {
                mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
                mAnimationScheduled = true;
            }
        }

start內部最終調用了mChoreographer.postCallback,其中有一個參數是this;至於什麼是Choreographer,暫時不用管;但是你需要知道一件事,其實我們的animationHandler是Runnable的子類,而 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);類似與handler發送消息,最終執行這個Runnable的run方法。

 

說這麼多,其實就是一句話,這裡調用了animationHandler的 run方法。

 

 public void run() {
            mAnimationScheduled = false;
            doAnimationFrame(mChoreographer.getFrameTime());
        }
private void doAnimationFrame(long frameTime) {
            while (mPendingAnimations.size() > 0) {
                ArrayList pendingCopy =
                        (ArrayList) 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);
                    } else {
                        mDelayedAnims.add(anim);
                    }
                }
            }
            //...省略了一些代碼
            

            // 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();
            }
        }

6-20行:while循環,遍歷所有在mPendingAnimations中的ObjectAnimator,依次調用anim.startAnimation(this);

 

在anim.startAnimation(this);內部其實主要就一行代碼:handler.mAnimations.add(this); 將當前動畫加入animationHandler的mAnimations集合;

26-29行:將animationHandler的mAnimations集合中的每個anim,加入到mTmpAnimations中;

30-35行:依次調用mTmpAnimations中的anim,anim.doAnimationFrame(frameTime)

doAnimationFrame(frameTime)上面已經分析過了,如果返回true,即doAnimationFrame的done為true,則將該動畫加入到結束動畫集合。

37-43行:循環調用mEndingAnims, mEndingAnims.get(i).endAnimation(this);內部,會將動畫移除mAnimations,回調動畫監聽接口onAnimationEnd;以及重置各種標志變量。46-48行:如果mAnimations不為null,則再次調用scheduleAnimation();哈哈,終於終於發現了,每隔多少幀調用一次動畫的地方了~~尼瑪這個scheduleAnimation,不就是animationHandler的 run方法調用的麼~~
前面已經描述過animationHandler的 run方法中通過計算屬性應該的值,反射設置;加上我們這裡的動畫沒結束,就會再次調用該run方法內部一致的方法~~~

 

 

搜噶,到此~~我們的屬性動畫的流程已經完美跑通了~~~

 

對了,看完以後,和我們文章開始的預期符合麼,其實我覺得差不多~~

 

4、總結

其實看源碼的目的,最終就是為了總結,尼瑪這麼長的代碼誰也記不住。。。所以看完記得總結:

ofInt中實例化了一個ObjectAnimator對象,然後設置了target,propName,values(PropertyValuesHolder) ;然後分別在setInterpolator,setDuration設置了Interpolator

和duration。其中setEvaluator是給PropertyValuesHolder,以及keyframeSet設置估值算法。

PropertyValueHolder實際上是IntPropertyValueHolder類型對象,包含propName,valueType,keyframeSet .

keyframeset中存了Keyframe集合,keyframe中存儲了(fraction , valuetype , value , hasValue)。

上述其實都是設置各種值什麼的。真正核心要看start~

start()中:

首先,步驟1:更新動畫各種狀態,然後初步計算fraction為(currentTime - mStartTime) / mDuration;然後將這個fraction交給我們的插值器計算後得到新的fraction,再將新的fraction交給我們的估值算法,估值算法根據開始、結束、fraction得到當前屬性(動畫作用的屬性)應該的值,最大調用反射進行設置;

當然了:start中還會根據動畫的狀態,如果沒有結束,不斷的調用scheduleAnimation();該方法內部利用mChoreographer不斷的去重復我們的上述步驟1。

 

好了,順便說一句,在看源碼的時候,一定要注意,你點進去的有可能不是真正運行時調用的,記得查看該方法子類,比如我們查看ObjectAnimator的方法,可能我們某個方法會跟到其父類ValueAnimator的方法,但是記得查看ObjectAnimator是否復寫了該方法~~如果復寫了,你該看的應該是ObjectAnimator的方法~~~

 

 

 


 

 

 

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved