轉載請註明出處(萬分感謝!):
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 幹什麽 文章
文章來源: