屬性動畫-Property Animation之ViewPropertyAnimator 你應該知道的一切

分類:IT技術 時間:2016-10-17

轉載請註明出處(萬分感謝!):
http://blog.csdn.net/Javazejian/article/details/52381558
出自【zejian的博客】

關聯文章:

走進絢爛多彩的屬性動畫-Property Animation(上篇)
走進絢爛多彩的屬性動畫-Property Animation之Interpolator和TypeEvaluator(下篇)
屬性動畫-Property Animation之ViewPropertyAnimator 你應該知道的一切
android布局動畫之animateLayoutChanges與LayoutTransition

??原本打算這篇作為屬性動畫的完結篇,但目前情況來看,估計無法完結,前兩天研究了一下ViewPropertyAnimator這個android 3.1版本後新添加的類,感覺挺有必要用一篇文章來記錄一下這個類,ViewPropertyAnimator本身也算不上什麽高級類,自然也不是什麽特殊技巧,那這個類到底是用來幹什麽的呢?這就是我們本篇的目的所在啦,接下來我們就來全面地了解一下ViewPropertyAnimator

1.ViewPropertyAnimator概述

??通過前兩篇的學習,我們應該明白了屬性動畫的推出已不再是針對於View而進行設計的了,而是一種對數值不斷操作的過程,我們可以將屬性動畫對數值的操作過程設置到指定對象的屬性上來,從而形成一種動畫的效果。雖然屬性動畫給我們提供了ValueAnimator類和ObjectAnimator類,在正常情況下,基本都能滿足我們對動畫操作的需求,但ValueAnimator類和ObjectAnimator類本身並不是針對View對象的而設計的,而我們在大多數情況下主要都還是對View進行動畫操作的,因此Google官方在Android 3.1系統中補充了ViewPropertyAnimator類,這個類便是專門為View動畫而設計的。當然這個類不僅僅是為提供View而簡單設計的,它存在以下優點:

  • 專門針對View對象動畫而操作的類。
  • 提供了更簡潔的鏈式調用設置多個屬性動畫,這些動畫可以同時進行的。
  • 擁有更好的性能,多個屬性動畫是一次同時變化,只執行一次UI刷新(也就是只調用一次invalidate,而n個ObjectAnimator就會進行n次屬性變化,就有n次invalidate)。
  • 每個屬性提供兩種類型方法設置。
  • 該類只能通過View的animate()獲取其實例對象的引用

??好~,下面我們來了解一下ViewPropertyAnimator常規使用

2.ViewPropertyAnimator常規使用

之前我們要設置一個View控件旋轉360的代碼是這樣:

ObjectAnimator.ofFloat(btn,"rotation",360).setDuration(200).start();

而現在我們使用ViewPropertyAnimator後是這樣:

btn.animate().rotation(360).setDuration(200);

??代碼是不是特簡潔?這裏我們來解析一下,首先必須用View#animate()方法來獲取一個ViewPropertyAnimator的對象實例,前面我們說過ViewPropertyAnimator支持鏈式操作,所以這裏直接通過rotation方法設置旋轉角度,再設置時間即可,有沒有發現連動畫的啟動都不用我們去操作!是的,ViewPropertyAnimator內部會自動去調用
對於View#animate()方法,這裏再說明一下,animate()方法是在Android 3.1系統上新增的一個方法,其作用就是返回ViewPropertyAnimator的實例對象,其源碼如下,一目了然:

 /**
 * This method returns a ViewPropertyAnimator object, which can be used to animate
 * specific properties on this View.
 *
 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
 */
public ViewPropertyAnimator animate() {
    if (mAnimator == null) {
        mAnimator = new ViewPropertyAnimator(this);
    }
    return mAnimator;
}

接著我們再來試試別的方法,同時設置一組動畫集合如下:

AnimatorSet set = new AnimatorSet();
set.playTogether( ObjectAnimator.ofFloat(btn,"alpha",0.5f),
        ObjectAnimator.ofFloat(btn,"rotation",360),
        ObjectAnimator.ofFloat(btn,"scaleX",1.5f),
        ObjectAnimator.ofFloat(btn,"scaleY",1.5f),
        ObjectAnimator.ofFloat(btn,"translationX",0,50),
        ObjectAnimator.ofFloat(btn,"translationY",0,50)
);
set.setDuration(5000).start();

使用ViewPropertyAnimator設置代碼如下:

 btn.animate().alpha(0.5f).rotation(360).scaleX(1.5f).scaleY(1.5f)
              .translationX(50).translationY(50).setDuration(5000);

??是不是已經深深地愛上ViewPropertyAnimator?真的太簡潔了!都快感動地哭出來了……先去廁所哭會…….好吧,ViewPropertyAnimator簡單用法講完了,這裏小結一下ViewPropertyAnimator的常用方法:

Method Discription
alpha(float value) 設置透明度,value表示變化到多少,1不透明,0全透明。
scaleY(float value) 設置Y軸方向的縮放大小,value表示縮放到多少。1表示正常規格。小於1代表縮小,大於1代表放大。
scaleX(float value) 設置X軸方向的縮放大小,value表示縮放到多少。1表示正常規格。小於1代表縮小,大於1代表放大。
translationY(float value) 設置Y軸方向的移動值,作為增量來控制View對象相對於它父容器的左上角坐標偏移的位置,即移動到哪裏。
translationX(float value) 設置X軸方向的移動值,作為增量來控制View對象相對於它父容器的左上角坐標偏移的位置。
rotation(float value) 控制View對象圍繞支點進行旋轉, rotation針對2D旋轉
rotationX (float value) 控制View對象圍繞X支點進行旋轉, rotationX針對3D旋轉
rotationY(float value) 控制View對象圍繞Y支點進行旋轉, rotationY針對3D旋轉
x(float value) 控制View對象相對於它父容器的左上角坐標在X軸方向的最終位置。
y(float value) 控制View對象相對於它父容器的左上角坐標在Y軸方向的最終位置
void cancel() 取消當前正在執行的動畫
setListener(Animator.AnimatorListener listener) 設置監聽器,監聽動畫的開始,結束,取消,重復播放
setupdateListener(ValueAnimator.AnimatorUpdateListener listener) 設置監聽器,監聽動畫的每一幀的播放
setInterpolator(TimeInterpolator interpolator) 設置插值器
setStartDelay(long startDelay) 設置動畫延長開始的時間
setDuration(long duration) 設置動畫執行的時間
withLayer() 設置是否開啟硬件加速
withStartAction(Runnable runnable) 設置用於動畫監聽開始(Animator.AnimatorListener)時運行的Runnable任務對象
withEndAction(Runnable runnable) 設置用於動畫監聽結束(Animator.AnimatorListener)時運行的Runnable任務對象

??以上便是ViewPropertyAnimator一些操作方法,其實上面很多屬性設置方法都對應著一個By結尾的方法,其變量則代表的是變化量,如下:

我們看看其中scaleY與scaleYBy的實現:

public ViewPropertyAnimator scaleY(float value) {
        animateProperty(SCALE_Y, value);
        return this;
    }

public ViewPropertyAnimator scaleYBy(float value) {
    animatePropertyBy(SCALE_Y, value);
    return this;
}

再看看animateProperty()與 animatePropertyBy()

 private void animateProperty(int constantName, float toValue) {
        float fromValue = http://blog.csdn.net/javazejian/article/details/getValue(constantName);
        float deltaValue = http://blog.csdn.net/javazejian/article/details/toValue - fromValue;
        animatePropertyBy(constantName, fromValue, deltaValue);
    }

 private void animatePropertyBy(int constantName, float byValue) {
        float fromValue = http://blog.csdn.net/javazejian/article/details/getValue(constantName);
        animatePropertyBy(constantName, fromValue, byValue);
    }

??看了源碼現在應該很清楚有By結尾(代表變化量的大小)和沒By結尾(代表變化到多少)的方法的區別了吧。好~,再來看看監聽器,實際上我們可以通過

setListener(Animator.AnimatorListener listener)
setUpdateListener(ValueAnimator.AnimatorUpdateListener listener)
設置自定義監聽器,而在ViewPropertyAnimator內部也有自己實現的監聽器,同樣我們可以看一下其實現源碼:

private class AnimatorEventListener
            implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
        @Override
        public void onAnimationStart(Animator animation) {
            //調用了設置硬件加速的Runnable
            if (mAnimatorSetupMap != null) {
                Runnable r = mAnimatorSetupMap.get(animation);
                if (r != null) {
                    r.run();
                }
                mAnimatorSetupMap.remove(animation);
            }
            if (mAnimatorOnStartMap != null) {
                  //調用我們通過withStartAction(Runnable runnable)方法設置的runnable
                Runnable r = mAnimatorOnStartMap.get(animation);
                if (r != null) {
                    r.run();
                }
                mAnimatorOnStartMap.remove(animation);
            }
            if (mListener != null) {
                //調用我們自定義的監聽器方法
                mListener.onAnimationStart(animation);
            }
        }



        @Override
        public void onAnimationCancel(Animator animation) {
            if (mListener != null) {
                //調用我們自定義的監聽器方法
                mListener.onAnimationCancel(animation);
            }
            if (mAnimatorOnEndMap != null) {
                mAnimatorOnEndMap.remove(animation);
            }
        }

        @Override
        public void onAnimationRepeat(Animator animation) {
            if (mListener != null) {
                //調用我們自定義的監聽器方法
                mListener.onAnimationRepeat(animation);
            }
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            mView.setHasTransientState(false);
            if (mListener != null) {
                //調用我們自定義的監聽器方法
                mListener.onAnimationEnd(animation);
            }
            if (mAnimatorOnEndMap != null) {
                  //調用我們通過withEndAction(Runnable runnable)方法設置的runnable
                Runnable r = mAnimatorOnEndMap.get(animation);
                if (r != null) {
                    r.run();
                }
                mAnimatorOnEndMap.remove(animation);
            }
            if (mAnimatorCleanupMap != null) {
               //移除硬件加速
                Runnable r = mAnimatorCleanupMap.get(animation);
                if (r != null) {
                    r.run();
                }
                mAnimatorCleanupMap.remove(animation);
            }
            mAnimatorMap.remove(animation);
        }

??由源碼我們知道當監聽器僅需要監聽動畫的開始和結束時,我們可以通過

withStartAction(Runnable runnable)
withEndAction(Runnable runnable)
方法來設置一些特殊的監聽操作。在AnimatorEventListener中的開始事件還會判斷是否開啟硬件加速,當然在動畫結束時也會去關閉硬件加速。我們可以通過ViewPropertyAnimator #withLayer()方法開啟硬件加速功能。到此對於ViewPropertyAnimator的常規使用方式已很清晰了。剩下的我們就來剖析剖析ViewPropertyAnimator內部到底是如何運作的,同時又是如何優化動畫性能的。

3.ViewPropertyAnimator原理解析

??我們先通過一副圖來大概了解一下ViewPropertyAnimator內部的整體運行工作原理(圖太小的話請右鍵在新頁面打開哈,不知為什麽markdown限制了大小 。。郁悶中。。):

我們這裏先給出整體執行流程(有個整體的概念就行哈,不理解也沒有關系,看完下面的分析,再回來來看看也是可以),然後再詳細分析:

  • 1.通過imageView.animate()獲取ViewPropertyAnimator對象。
  • 2.調用alpha、translationX等方法,返回當前ViewPropertyAnimator對象,可以繼續鏈式調用
  • 3.alpha、translationX等方法內部最終調用animatePropertyBy(int constantName, float startValue, float byValue)方法
  • 4.在animatePropertyBy方法中則會將alpha、translationX等方法的操作封裝成NameVauleHolder,並將每個NameValueHolder對象添加到準備列表mPendingAnimations中。
  • 5.animatePropertyBy方法啟動mAnimationStarter,調用startAnimation,開始動畫。
  • 6.startAnimation方法中會創建一個ValueAnimator對象設置內部監聽器AnimatorEventListener,並將mPendingAnimations和要進行動畫的屬性名稱封裝成一個PropertyBundle對象,最後mAnimatorMap保存當前Animator和對應的PropertyBundle對象。該Map將會在animatePropertyBy方法和Animator監聽器mAnimatorEventListener中使用,啟動動畫。
  • 7.在動畫的監聽器的onAnimationUpdate方法中設置所有屬性的變化值,並通過RenderNode類優化繪制性能,最後刷新界面。

??有了整體概念後,現在我們沿著該工作流程圖的路線來分析ViewPropertyAnimator內部執行過程,從上圖可以看出,通過View#animate()獲取到ViewPropertyAnimator實例後,可以通過ViewPropertyAnimator提供的多種方法來設置動畫,如translationX()、scaleX()等等,而當調用完這些方法後,其內部最終則會通過多次調用animatorPropertyBy(),我們先看看animatePropertyBy方法源碼:

/**
     * Utility function, called by animateProperty() and animatePropertyBy(), which handles the
     * details of adding a pending animation and posting the request to start the animation.
     *
     * @param constantName The specifier for the property being animated
     * @param startValue The starting value of the property
     * @param byValue The amount by which the property will change
     */
    private void animatePropertyBy(int constantName, float startValue, float byValue) {
        // First, cancel any existing animations on this property
        //判斷該屬性上是否存在運行的動畫,存在則結束。
        if (mAnimatorMap.size() > 0) {
            Animator animatorToCancel = null;
            Set<Animator> animatorSet = mAnimatorMap.keySet();
            for (Animator runningAnim : animatorSet) {
                PropertyBundle bundle = mAnimatorMap.get(runningAnim);
                if (bundle.cancel(constantName)) {// 結束對應屬性動畫
                    // property was canceled - cancel the animation if it's now empty
                    // Note that it's safe to break out here because every new animation
                    // on a property will cancel a previous animation on that property, so
                    // there can only ever be one such animation running.
                    if (bundle.mPropertyMask == NONE) {//判斷是否還有其他屬性
                        // the animation is no longer changing anything - cancel it
                        animatorToCancel = runningAnim;
                        break;
                    }
                }
            }
            if (animatorToCancel != null) {
                animatorToCancel.cancel();
            }
        }
//將要執行的屬性的名稱,開始值,變化值封裝成NameValuesHolder對象
        NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
        //添加到準備列表中
        mPendingAnimations.add(nameValuePair);
        mView.removeCallbacks(mAnimationStarter);
        mView.postOnAnimation(mAnimationStarter);
    }

??從源碼可以看出,animatePropertyBy方法主要幹了以下幾件事:

  • 首先會去當前屬性是否還有在動畫在執行,如果有則先結束該屬性上的動畫,保證該屬性上只有一個Animator在進行動畫操作。
  • 將本次動畫需要執行的動畫屬性封裝成一個NameValueHolder對象
  • 將每個NameValuesHolder對象添加到mPendingAnimations的準備列表中

??NameValuesHolder對象是一個內部類,其相關信息如下:
NameValueHolder:內部類,封裝每個要進行動畫屬性值開始值和變化值,比如translationX(200),那麽這個動畫的屬性值、開始值和變化值將被封裝成一個NameValueHolder,其源碼也非常簡單:

static class NameValuesHolder {
        int mNameConstant;//要進行動畫的屬性名稱
        float mFromValue;//開始值
        float mDeltaValue;//變化值
        NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
            mNameConstant = nameConstant;
            mFromValue = http://blog.csdn.net/javazejian/article/details/fromValue;
            mDeltaValue = deltaValue;
        }
    }

??而mPendingAnimations的相關信息如下:
mPendingAnimations:裝載的是準備進行動畫的屬性值(NameValueHolder)所有列表,也就是每次要同時進行動畫的全部屬性的集合

ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();

??當添加完每個要運行的屬性動畫後,則會通過mAnimationStarter對象去調用

startAnimation()
,啟動動畫。
Runnable mAnimationStarter: 用來執行動畫的Runnable。它會執行startAnimation方法,而在startAnimation方法中會通過animator.start()啟動動畫,源碼非常簡潔:

private Runnable mAnimationStarter = new Runnable() {
        @Override
        public void run() {
            startAnimation();
        }
};

接著我們看看startAnimation()的源碼:

/**
 * Starts the underlying Animator for a set of properties. We use a single animator that
 * simply runs from 0 to 1, and then use that fractional value to set each property
 * value accordingly.
 */
private void startAnimation() {
    if (mRTBackend != null && mRTBackend.startAnimation(this)) {
        return;
    }
    mView.setHasTransientState(true);
    //創建ValueAnimator
    ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
    //clone一份mPendingAnimations賦值給nameValueList
    ArrayList<NameValuesHolder> nameValueList =
            (ArrayList<NameValuesHolder>) mPendingAnimations.clone();
     //賦值完後清空
    mPendingAnimations.clear();
    //用於標識要執行動畫的屬性
    int propertyMask = 0;
    int propertyCount = nameValueList.size();
    //遍歷所有nameValuesHolder,取出其屬性名稱mNameConstant,
    //執行"|"操作並最終賦值propertyMask
    for (int i = 0; i < propertyCount; ++i) {
        NameValuesHolder nameValuesHolder = nameValueList.get(i);
        propertyMask |= nameValuesHolder.mNameConstant;
    }
    //創建PropertyBundle,並添加到mAnimatorMap中
    mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
    if (mPendingSetupAction != null) {
        //設置硬件加速
        mAnimatorSetupMap.put(animator, mPendingSetupAction);
        mPendingSetupAction = null;
    }
    if (mPendingCleanupAction != null) {
       //移除硬件加速
        mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
        mPendingCleanupAction = null;
    }
    if (mPendingOnStartAction != null) {
        //設置開始的動畫(監聽器的開始方法中調用)
        mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
        mPendingOnStartAction = null;
    }
    if (mPendingOnEndAction != null) {
        //設置結束後要進行的下一個動畫(監聽器的結束方法中調用)
        mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
        mPendingOnEndAction = null;
    }
    //添加內部監聽器
    animator.addUpdateListener(mAnimatorEventListener);
    animator.addListener(mAnimatorEventListener);
    //判斷是否延長開始
    if (mStartDelaySet) {
        animator.setStartDelay(mStartDelay);
    }
    //執行動畫的實現
    if (mDurationSet) {
        animator.setDuration(mDuration);
    }
    //設置插值器
    if (mInterpolatorSet) {
        animator.setInterpolator(mInterpolator);
    }
    //開始執行動畫
    animator.start();
}

??我們上面的註釋非常全面,這裏startAnimation主要做下面幾件事:

  • 創建Animator,變化值從0到1,設置內部監聽器mAnimatorEventListener。
  • clone一份mPendingAnimations列表,並計算屬性值標記propertyMask,封裝成PropertyBundle對象。
  • 使用mAnimatorMap保存當前Animator和對應的PropertyBundle對象。該Map將會在animatePropertyBy方法和Animator監聽器mAnimatorEventListener中使用。
  • 啟動animator動畫。


??關於PropertyBundle的分析如下:
PropertyBundle: 內部類,存放著將要執行的動畫的屬性集合信息,每次調用

animator.start();
前,都會將存放在mPendingAnimations的clone一份存入PropertyBundle的內部變量mNameValuesHolder中,然後再將遍歷mPendingAnimations中的NameValueHolder類,取出要執行的屬性進行”|”操作,最後記錄成一個mPropertyMask的變量,存放在PropertyBundle中,PropertyBundle就是最終要執行動畫的全部屬性的封裝類,其內部結構如下圖

AnimatorEventListener: ViewPropertyAnimator內部的監聽器。這個類實現了Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener接口。我們前面已經分享過它的部分源碼,這個類還有一個onAnimationUpdate()的監聽方法,這個方法我們放在後面解析,它是動畫執行的關鍵所在。

HashMap mAnimatorMap: 存放PropertyBundle類的Map。這個Map中存放的是正在執行的動畫的PropertyBundle,這個PropertyBundle包含這本次動畫的所有屬性的信息。最終在AnimatorEventListener的onAnimationUpdate()方法中會通過這個map獲取相應的屬性,然後不斷更新每幀的屬性值以達到動畫效果。通過前面對animatePropertyBy方法的分析,我們可以知道該Map會保證當前只有一個Animator對象對該View的屬性進行操作,不會存在兩個Animator在操作同一個屬性,其聲明如下:

private HashMap<Animator, PropertyBundle> mAnimatorMap =
?        new HashMap<Animator, PropertyBundle>();

??最後我們看看動畫是在哪裏執行的,根據我們前面的原理圖,內部監聽器的onAnimationUpdate()方法將會被調用(當然內部監聽器AnimatorEventListener實現了兩個動畫監聽接口,其開始,結束,重復,取消4個方法也會被調用,這個我們前面已分析過)。

@Override
        public void onAnimationUpdate(ValueAnimator animation) {
        //取出當前Animator對應用propertyBundle對象
            PropertyBundle propertyBundle = mAnimatorMap.get(animation);
            if (propertyBundle == null) {
                // Shouldn't happen, but just to play it safe
                return;
            }
        //是否開啟了硬件加速
            boolean hardwareAccelerated = mView.isHardwareAccelerated();

            // alpha requires slightly different treatment than the other (transform) properties.
            // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
            // logic is dependent on how the view handles an internal call to onSetAlpha().
            // We track what kinds of properties are set, and how alpha is handled when it is
            // set, and perform the invalidation steps appropriately.
            boolean alphaHandled = false;
            if (!hardwareAccelerated) {
                mView.invalidateParentCaches();
            }
            //取出當前的估算值(插值器計算值)
            float fraction = animation.getAnimatedFraction();
            int propertyMask = propertyBundle.mPropertyMask;
            if ((propertyMask & TRANSFORM_MASK) != 0) {
                mView.invalidateViewProperty(hardwareAccelerated, false);
            }
            //取出所有要執行的屬性動畫的封裝對象NameValuesHolder
            ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
            if (valueList != null) {
                int count = valueList.size();
                //遍歷所有NameValuesHolder,計算變化值,並設置給對應的屬性
                for (int i = 0; i < count; ++i) {
                    NameValuesHolder values = valueList.get(i);
                    float value = http://blog.csdn.net/javazejian/article/details/values.mFromValue + fraction * values.mDeltaValue;
                    if (values.mNameConstant == ALPHA) {
                        alphaHandled = mView.setAlphaNoInvalidation(value);
                    } else {
                        setValue(values.mNameConstant, value);
                    }
                }
            }
            if ((propertyMask & TRANSFORM_MASK) != 0) {
                if (!hardwareAccelerated) {
                    mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
                }
            }
            // invalidate(false) in all cases except if alphaHandled gets set to true
            // via the call to setAlphaNoInvalidation(), above
            if (alphaHandled) {
                mView.invalidate(true);
            } else {
                mView.invalidateViewProperty(false, false);
            }
            if (mUpdateListener != null) {
                mUpdateListener.onAnimationUpdate(animation);
            }
        }

??onAnimationUpdate方法主要做了以下幾件事:

  • 取出當前Animator對應用propertyBundle對象並獲取當前的估算值(插值器計算值),用於後續動畫屬性值的計算
  • 從propertyBundle取出要進行動畫的屬性列表 ArrayList<NameValuesHolder> valueList
  • 遍歷所有NameValuesHolder,計算變化值,並通過setValue設置給對應的屬性,如果是ALPHA,則會特殊處理一下,最終形成動畫效果

setValue方法源碼:

 private void setValue(int propertyConstant, float value) {
        final View.TransformationInfo info = mView.mTransformationInfo;
        final RenderNode renderNode = mView.mRenderNode;
        switch (propertyConstant) {
            case TRANSLATION_X:
                renderNode.setTranslationX(value);
                break;
            case TRANSLATION_Y:
                renderNode.setTranslationY(value);
                break;
            case TRANSLATION_Z:
                renderNode.setTranslationZ(value);
                break;
            case ROTATION:
                renderNode.setRotation(value);
                break;
            case ROTATION_X:
                renderNode.setRotationX(value);
                break;
            case ROTATION_Y:
                renderNode.setRotationY(value);
                break;
            case SCALE_X:
                renderNode.setScaleX(value);
                break;
            case SCALE_Y:
                renderNode.setScaleY(value);
                break;
            case X:
                renderNode.setTranslationX(value - mView.mLeft);
                break;
            case Y:
                renderNode.setTranslationY(value - mView.mTop);
                break;
            case Z:
                renderNode.setTranslationZ(value - renderNode.getElevation());
                break;
            case ALPHA:
                info.mAlpha = value;
                renderNode.setAlpha(value);
                break;
        }
    }

??從源碼可以看出實際上都會把屬性值的改變設置到renderNode對象中,而RenderNode類則是一個可以優化繪制流程和繪制動畫的類,該類可以提升優化繪制的性能,其內部操作最終會去調用到Native層方法,這裏我們就不深追了。
??最後這裏我們再回憶一下前面給出的整體流程說明:

  • 1.通過imageView.animate()獲取ViewPropertyAnimator對象。
  • 2.調用alpha、translationX等方法,返回當前ViewPropertyAnimator對象,可以繼續鏈式調用
  • 3.alpha、translationX等方法內部最終調用animatePropertyBy(int constantName, float startValue, float byValue)方法
  • 4.在animatePropertyBy方法中則會將alpha、translationX等方法的操作封裝成NameVauleHolder,並將每個NameValueHolder對象添加到準備列表mPendingAnimations中。
  • 5.animatePropertyBy方法啟動mAnimationStarter,調用startAnimation,開始動畫。
  • 6.startAnimation方法中會創建一個ValueAnimator對象設置內部監聽器AnimatorEventListener,並將mPendingAnimations和要進行動畫的屬性名稱封裝成一個PropertyBundle對象,最後mAnimatorMap保存當前Animator和對應的PropertyBundle對象。該Map將會在animatePropertyBy方法和Animator監聽器mAnimatorEventListener中使用,啟動動畫。
  • 7.在動畫的監聽器的onAnimationUpdate方法中設置所有屬性的變化值,並通過RenderNode類優化繪制性能,最後刷新界面。

??現在應該比較清晰了吧,以上就是ViewPropertyAnimator內部的大概執行流程。好~,ViewPropertyAnimator介紹到這。

關聯文章:
走進絢爛多彩的屬性動畫-Property Animation(上篇)
走進絢爛多彩的屬性動畫-Property Animation之Interpolator和TypeEvaluator(下篇)
屬性動畫-Property Animation之ViewPropertyAnimator 你應該知道的一切


Tags: Android android Google 幹什麽 文章

文章來源:


ads
ads

相關文章
ads

相關文章

ad