ViewPropertyAnimator概述
属性动画已不再是针对于View而进行设计的了,而是一种对数值不断操作的过程,我们可以将属性动画对数值的操作过程设置到指定对象的属性上来,从而形成一种动画的效果。虽然属性动画给我们提供了ValueAnimator类和ObjectAnimator类,在正常情况下,基本都能满足我们对动画操作的需求,但ValueAnimator类和ObjectAnimator类本身并不是针对View对象的而设计的,而我们在大多数情况下主要都还是对View进行动画操作的,因此Google官方在Android 3.1系统中补充了ViewPropertyAnimator类,这个类便是专门为View动画而设计的。
优点:
- 专门针对View对象动画而操作的类。
- 提供了更简洁的链式调用设置多个属性动画,这些动画可以同时进行的。
- 拥有更好的性能,多个属性动画是一次同时变化,只执行一次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度。再调用一次的话,由于已经到20度的位置,便不在有变化。
- rotationXBy(20) 改变某个值的量。 旋转20度。再调用一次的话,继续旋转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);
// 如果在该属性上已经有动画,则结束该属性上的动画。
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给系统,然后系统按顺序调用,假如系统很闲,post了立马就start,那么下一个属性设置的时候呢,怎么保证每个属性的设置都放到集合里了才开始start?
mView.postOnAnimation(mAnimationStarter);
}