ViewPropertyAnimator概述
屬性動畫已不再是針對于View而進行設計的了,而是一種對數(shù)值不斷操作的過程,我們可以將屬性動畫對數(shù)值的操作過程設置到指定對象的屬性上來,從而形成一種動畫的效果。雖然屬性動畫給我們提供了ValueAnimator類和ObjectAnimator類,在正常情況下,基本都能滿足我們對動畫操作的需求,但ValueAnimator類和ObjectAnimator類本身并不是針對View對象的而設計的,而我們在大多數(shù)情況下主要都還是對View進行動畫操作的,因此Google官方在Android 3.1系統(tǒng)中補充了ViewPropertyAnimator類,這個類便是專門為View動畫而設計的。
優(yōu)點:
- 專門針對View對象動畫而操作的類。
- 提供了更簡潔的鏈式調用設置多個屬性動畫,這些動畫可以同時進行的。
- 擁有更好的性能,多個屬性動畫是一次同時變化,只執(zhí)行一次UI刷新(也就是只調用一次invalidate,而n個ObjectAnimator就會進行n次屬性變化,就有n次invalidate)。
- 每個屬性提供兩種類型方法設置。scaleX()/scaleXBy()
- 該類只能通過View的animate()獲取其實例對象的引用。
用法:鏈式調用,自動start,同時一次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();
//自動調用start方法
btn.animate().alpha(0.5f).rotation(360).scaleX(1.5f).scaleY(1.5f)
.translationX(50).translationY(50).setDuration(5000);
每個屬性,兩種類型方法設置:
- rotationX(20) 改變到某個值。 旋轉到20度。再調用一次的話,由于已經(jīng)到20度的位置,便不在有變化。
- rotationXBy(20) 改變某個值的量。 旋轉20度。再調用一次的話,繼續(xù)旋轉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等方法,到最后都是調用該方法-----------------------------------
/**
* 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)有動畫,則結束該屬性上的動畫。
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類,但是每次都把原來的移除了,始終都在維護一個最新的集合post。
//TODO ??? post給系統(tǒng),然后系統(tǒng)按順序調用,假如系統(tǒng)很閑,post了立馬就start,那么下一個屬性設置的時候呢,怎么保證每個屬性的設置都放到集合里了才開始start?
mView.postOnAnimation(mAnimationStarter);
}
后續(xù)監(jiān)聽什么的,還沒研究。 資料鏈接。
原理流程:
image
image