轉載請註明出處(萬分感謝!):
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 = getValue(constantName);
float deltaValue = toValue - fromValue;
animatePropertyBy(constantName, fromValue, deltaValue);
}
private void animatePropertyBy(int constantName, float byValue) {
float fromValue = 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 = 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 = 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 你應該知道的一切