ViewPropertyAnimator概述
屬性動(dòng)畫已不再是針對于View而進(jìn)行設(shè)計(jì)的了,而是一種對數(shù)值不斷操作的過程西傀,我們可以將屬性動(dòng)畫對數(shù)值的操作過程設(shè)置到指定對象的屬性上來买乃,從而形成一種動(dòng)畫的效果显拜。雖然屬性動(dòng)畫給我們提供了ValueAnimator類和ObjectAnimator類枢泰,在正常情況下笨蚁,基本都能滿足我們對動(dòng)畫操作的需求凶朗,但ValueAnimator類和ObjectAnimator類本身并不是針對View對象的而設(shè)計(jì)的瓷胧,而我們在大多數(shù)情況下主要都還是對View進(jìn)行動(dòng)畫操作的,因此Google官方在Android 3.1系統(tǒng)中補(bǔ)充了ViewPropertyAnimator類棚愤,這個(gè)類便是專門為View動(dòng)畫而設(shè)計(jì)的搓萧。
優(yōu)點(diǎn):
- 專門針對View對象動(dòng)畫而操作的類杂数。
- 提供了更簡潔的鏈?zhǔn)秸{(diào)用設(shè)置多個(gè)屬性動(dòng)畫,這些動(dòng)畫可以同時(shí)進(jìn)行的瘸洛。
- 擁有更好的性能揍移,多個(gè)屬性動(dòng)畫是一次同時(shí)變化,只執(zhí)行一次UI刷新(也就是只調(diào)用一次invalidate,而n個(gè)ObjectAnimator就會進(jìn)行n次屬性變化反肋,就有n次invalidate)那伐。
- 每個(gè)屬性提供兩種類型方法設(shè)置。scaleX()/scaleXBy()
- 該類只能通過View的animate()獲取其實(shí)例對象的引用石蔗。
用法:鏈?zhǔn)秸{(diào)用喧锦,自動(dòng)start,同時(shí)一次UI刷新抓督, 簡化流程提高效率燃少。
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();
//自動(dòng)調(diào)用start方法
btn.animate().alpha(0.5f).rotation(360).scaleX(1.5f).scaleY(1.5f)
.translationX(50).translationY(50).setDuration(5000);
每個(gè)屬性,兩種類型方法設(shè)置:
- rotationX(20) 改變到某個(gè)值铃在。 旋轉(zhuǎn)到20度阵具。再調(diào)用一次的話,由于已經(jīng)到20度的位置定铜,便不在有變化阳液。
- rotationXBy(20) 改變某個(gè)值的量。 旋轉(zhuǎn)20度揣炕。再調(diào)用一次的話帘皿,繼續(xù)旋轉(zhuǎn)20度,到40度的位置畸陡。
public ViewPropertyAnimator scaleY(float value) {
animateProperty(SCALE_Y, value);
return this;
}
public ViewPropertyAnimator scaleYBy(float value) {
animatePropertyBy(SCALE_Y, value);
return this;
-----------------------------------------------------------------------------
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);
}
----------scale/rotation/alpha等方法鹰溜,到最后都是調(diào)用該方法-----------------------------------
/**
* 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);
// 如果在該屬性上已經(jīng)有動(dòng)畫,則結(jié)束該屬性上的動(dòng)畫丁恭。
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 nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
mPendingAnimations.add(nameValuePair);
mView.removeCallbacks(mAnimationStarter);
//雖然每次操作屬性都post了該Runnable類,但是每次都把原來的移除了牲览,始終都在維護(hù)一個(gè)最新的集合post墓陈。
//TODO ?第献?贡必? post給系統(tǒng),然后系統(tǒng)按順序調(diào)用庸毫,假如系統(tǒng)很閑仔拟,post了立馬就start,那么下一個(gè)屬性設(shè)置的時(shí)候呢岔绸,怎么保證每個(gè)屬性的設(shè)置都放到集合里了才開始start理逊?
mView.postOnAnimation(mAnimationStarter);
}