概述
属性动画,顾名思义-动态改变对象的属性,以此变化来产生某种效果。 这里的对象可是任何对象,并不限定是View控件。
-
属性动画是Android 3.0(API 11)增加的,为何增加?有何意义?
- 你一定还记得在view animation 中,交互不友好(比如view的位置改变了,但是点击事件还在原来的位置)
- view animation 能让view动起来的效果有限,属性动画可是打着能改变任何对象的任何属性出场的,这样就可以实现复杂高级效果了。
-
系统为我们提供了属性动画哪些用法?出了具体表现在这些类,也支持XML中定义使用。
- ObjectAnimator
- PropertyHolder
- ValueAnimator
- AnimatorSet
- Animator.AnimatorListener
- ValueAnimator.AnimatorUpdateListener
属性动画中也要用到view动画中的差值器等API,也独有估值器
ObjectAnimator
在这个类中,通过调用ObjectAnimator的工厂方法,传入对应的参数即可,举个简单的用法来看具体怎么使用
这样的效果用属性动画也是非常容易实现的
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageview, "translationX", 0f, imageview.getWidth());
// 指定一个时间差值器(TimeInpolator),ObjectAnimator默认的是LinearInpolator
objectAnimator1.setInterpolator(new AccelerateDecelerateInterpolator());
objectAnimator1.setDuration(1000);
objectAnimator1.start();
关于ofFloat(Object target, String propertyName, float... values)
第一个参数是要操纵的对象,第二个是操纵对象的属性名,第三个是一个可变数组参数,表示属性的取值变化的过程
列举view的一些常见可以直接用的属性值
view偏移量: translationX 、translationY
view2D和3D旋转角度: rotation、rotationX、rotationY
view的2D缩放比例: scaleX、 scaleY
view的旋转和缩放的中心点,默认是view的中心点:pivotX、pivotY
view的坐标: x 、y
view的透明度: alpha
值得注意的是ObjectAnimator
:
- 操纵的属性必须具有
set
,因为() ObjectAnimator
在动态改变属性的过程中,会去通过set方法来改变这个属性。如果操纵的属性没有set方法,官方给出三种建议:- 如果你有权限的话就去给这个属性添加一个set方法
- 可以通过自定义一个属性类或者包装类,来间接给这个属性增加set方法
- 使用
ValueAnimator
来代替
- 对于这个可变参数,
values...
如果仅仅设置了一个参数,会被认为这个值是变化过程的结束值。此刻ObjectAnimator
会自动去通过get
来获得变化的起始值,这时就要求操作的属性必须具有get方法()
这里我们举个例子,操作一个自定义的对象
public class Person {
private int age;
public void setAge(int age) {
this.age = age;
Log.d("age", "set年龄" + age);
}
public int getAge() {
Log.d("age", "get年龄" + age);
return age;
}
}
这个时候我们去动画的改变它
ObjectAnimator objectAnimator;
// 1.属性动画可以对任意一个对象的属性动态改变
objectAnimator = ObjectAnimator.ofInt(new Person(), "age",5, 8);
objectAnimator.start();
观察这个时候的log
和我们预想的一样,动态改变了这个年龄值,哈哈
如果我们对可变参数只设置一个参数呢?
ObjectAnimator objectAnimator;
// 1.属性动画可以对任意一个对象的属性动态改变
objectAnimator = ObjectAnimator.ofInt(new Person(), "age", 4);
objectAnimator.start();
这个时候的log 显示表明调用了get方法获得初始值
虽然上面这个改变属性值没有实际意义,但是很清晰的展示了属性动画的魅力和变化过程。
你对为什么一个数值打印那么多遍感到很奇怪?
其实这就是属性动画中有估值器(Evaluator)这个概念,这里我给采用的是ofInt
对应的其实是IntEvaluator
,这是ObjectAnimator内部会去判断,可以去源码中查看。
同理如果ofFloat
对应的就是FloatEvaluator
当然你也可以ofObject
传入自己想要的估值器
那么这个时候你把Person
的age
属性改成float, 并且动画采用ofFloat
,结果你会发现会一步一步接近最后的值。
PropertyValuesHolder
如果同时改变多个属性呢?
可以直接构造多个ObjetAnimator
然后调用start
. 因为他们是异步的,这些动画会同时执行
objectAnimator1.setInterpolator(new AccelerateDecelerateInterpolator());
objectAnimator1.setDuration(1000);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageview, "translationY", 0f, imageview.getHeight());
objectAnimator2.setInterpolator(new AccelerateDecelerateInterpolator());
objectAnimator2.setDuration(1000);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageview, "rotationX", 0f, 360);
objectAnimator3.setInterpolator(new AccelerateDecelerateInterpolator());
objectAnimator3.setDuration(2000);
objectAnimator1.start();
objectAnimator2.start();
objectAnimator3.start();;
还可以使用PropertyValuesHolder
,然后调用的ObjectAnimator.ofPropertyValuesHolder
PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX",0f,imageview.getWidth());
PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("translationY",0f,imageview.getHeight());
PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("rotationX",0f,360f);
ObjectAnimator.ofPropertyValuesHolder(imageview, p1,p2,p3).setDuration(2000).start();
在上面的例子中,那如果我想控制他们的播放顺序呢?
AnimatorSet
这个效果是先同时x和y方向平移动画,然后在执行旋转
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageview, "translationX", 0f, imageview.getWidth());
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageview, "translationY", 0f, imageview.getHeight());
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageview, "rotationX", 0f, 360);
AnimatorSet set = new AnimatorSet();
set.setDuration(2000);
set.setInterpolator(new LinearInterpolator());
//set.playTogether(objectAnimator1,objectAnimator2, objectAnimator3);
//set.playSequentially(objectAnimator1,objectAnimator2, objectAnimator3);
set.play(objectAnimator1).with(objectAnimator2).before(objectAnimator3); objectAnimator3);
set.start();
可以将注释部分观察效果。AnimatorSet
需要说明几点:
-
playSequentially
是单独顺序播放 -
play
配合with
、before
、after
来按照这些规则播放动画 -
playTogether
动画同时播放
ValueAnimator的使用
通过上面的那个类关系图,ValueAnimator
是ObjectAnimator
的父类,实际上ObjectAnimator
是更加具体化了ValueAnimator
,实现了一系列的既定效果,更加方便的使用。那么上文提到如果一个属性没有set方法可以用ValueAnimator
来代替.
什么意思呢?其实就是说ValueAnimator
,它并不要求你非要指定什么属性,注重的是值的变化,然后可以监听这些值的变化过程,从而自己来根据这些值,产生你自己需要的效果。比如你要做一个计时器,这个时候你可以ofInt在监听里面去设置UI 显示倒计时的数值即可。
这里看一下如何监听等常规思路:
ValueAnimator valueAnimator = ValueAnimator.ofInt(1,15);// ValueAnimator ,ofInt,ofFloat,ofObject
// valueAnimator.setEvaluator(new IntEvaluator()); // 设置估值器
valueAnimator.setEvaluator(new TypeEvaluator() {
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
// 这里自定义了一个估值器,就是在int估值器的基础上加一个1
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt)+1);
}
});
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.d("smart","变化的值:" +animation.getAnimatedValue());
}
});
valueAnimator.setDuration(3000);
valueAnimator.start();
估值器
-
系统定义的估值器:
- IntEvaluator 计算整型
- FloatEvaluator 计算float型
- ArgbEvaluator 计算颜色
- TypeEvaluator 是一个接口,自定义估值器需要实现它
-
如何自定义一个估值器
public interface TypeEvaluator
{ public T evaluate(float fraction, T startValue, T endValue); } 实现这个接口,确定泛型的返回值T。
至此 ,属性动画的基本概念叙述完毕!