在Android3.0以前的动画框架Animation存在着局限性:只能改变显示的位置,但是不能真正的更改View的位置,所以在Android3.0以后Google就推出了属性动画(Animator)
在Animator框架动画中使用最多的就是ObjectAnimator和AnimatorSet。使用ObjectAnimator来进行控制,一个ObjectAnimator只能控制一个对象的一个值,而使用多个ObjectAnimator组合到一个AnimatorSet当中形成一个动画的集合。其中最重要的是属性动画通过调用属性的get/set方法来真实的控制一个View的属性,所以基本的的动画都可以用属性动画来实现
ObjectAnimator
创建一个ObjectAnimor只需要调用ObjectAnimator的静态工厂方法就可以直接返回一个ObjectAnimator对象,其属性有需要控制的对象,和对象的属性名(动画的名称),但是这个属性必须要有get、set方法,因为在内部会调用Java的反射机制来调用set函数修改属性值
看一个小实例
把一个Button向右方平移300,如图:
代码如下:
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
/**
* 创建ObjectAnimator对象
* 设置对象和对象属性还有值
*/
ObjectAnimator oa = ObjectAnimator.ofFloat(btn, "translationX", 300);
oa.setDuration(300); //设置时间为300ms
oa.start();
}
});
这里我们首先通过ObjectAnimator的静态工厂方法创建了一个对象,这里的三个参数:第一个参数则是需要曹工的对象,第二个是要操纵的属性,第三个是一个可变数组,这里我们只给了一个参数300,最后调用start()方法就可以看到动画啦。
常用的可以直接使用的属性动画的值
- translationX/translationY :作为一种增量来控制对象从它的父布局的左上角偏移的位置
- rotation、rotationX、rotationY:控制对象围绕支点来进行2D和3D旋转
- pivotX、pivotY:这两个属性控制着对象的支点位置,围绕着这个支点进行旋转和缩放,在默认情况下支点就是该对象的中心点
- x、y:这两个属性描述了对象在他容器中的最终位置,他是最初的左上角坐标和translationX、translationY值的累积和
- alpha:透明度,默认值是1(不透明),0代表完全透明
可以看的出来大部分的动画都包含了,但是如果说有的属性没有get/set方法,那是不是就不能更改了呢?我们可以写一个自定义的属性类或者包装类来间接的给这个属性添加get/set方法。
来看一下包装类,代码如下:
public class WrapperView {
private View mTarget;
public WrapperView(View mTarget) {
this.mTarget = mTarget;
}
public int getWidth(){
return mTarget.getLayoutParams().width;
}
public void setWidth(int width){
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
通过以上的代码就给一个width属性进行了包装,等到使用的时候只需要通过包装类就可以间接的调用到get/set方法了,如下:
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
/**
* 创建ObjectAnimator对象
* 设置对象和对象属性还有值
*/
ObjectAnimator oa = ObjectAnimator.ofInt(new WrapperView(btn), "width", 500);
oa.setDuration(300);
oa.start();
}
});
还是熟悉的配方,还是原来的味道!这里只不过我们换了一下创建ObjectAnimator对象的方法,因为我们的setWidth方法里的参数是int类型的,所以我们的静态工厂方法需要使用ofInt()方法,如果还是使用ofFloat()的话会提示W/PropertyValuesHolder: Method setWidth() with type float not found on target class class com.androidqunyingzhuan.WrapperView
。没有找到类型为float的set方法,运行一下程序:
PropertyValuesHolder
这个属性类似于AnimationSet,在属性动画中,如果针对同一个对象的多个属性并且同时作用多种动画就可以使用PropertyValuesHolder实现。比如在平移的过程中同时改变X、Y轴的缩放,代码如下:
PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX", 300);
PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("scaleX", 1, 0, 1);
PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("scaleY", 1, 0, 1);
ObjectAnimator.ofPropertyValuesHolder(btn, p1, p2, p3).setDuration(1000).start();
这样我们就把这三个动画同时作用在一个对象上了,运行程序:
ValueAnimator
ValueAnimator在属性动画中是非常重要的,它是属性动画的核心所在,ObjectAnimator也是继承的ValueAnimator
ValueAnimator不提供任何动画的实现,他像是一个数值发生器,用来产生具有一定规律的数字,来让调用者控制动画的实现过程,通常情况下在ValueAnimator的AnimatorUpdateListener中监听数值的变化,来完成动画的变换
ValueAnimator va = ValueAnimator.ofFloat(0, 100);
va.setDuration(2000).start();
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
btn.setText(valueAnimator.getAnimatedValue() + "");
}
});
我们通过ofFloat()方法来创建了一个ValueAnimator对象,设置值的变换是从0f到100f,设置时间为2秒,然后我们在AnimatorUpdateListener中获取当前值让btn来显示,效果如下:
动画事件的监听
Android提供给我们了一个接口,可以很方便的监听到一个动画的所有过程:
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
但是大部分的时候我们只会关心动画完成之后我们需要做些什么,所以Android还提供了一个适配器来让我们选择
oa.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
AnimatorSet
对于在一个对象同一时间作用多个属性动画效果前面已经用PropertyValuesHolder实现了这样的效果,但是AnimatorSet不仅能实现这样的效果,同时能实现更为精确的顺序控制,下面我们用AnimatorSet来实现上面PropertyValuesHolder演示的动画。代码如下:
ObjectAnimator a1 = ObjectAnimator.ofFloat(btn, "translationX", 300);
ObjectAnimator a2 = ObjectAnimator.ofFloat(btn, "scaleX", 1, 0, 1);
ObjectAnimator a3 = ObjectAnimator.ofFloat(btn, "scaleY", 1, 0, 1);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
set.playTogether(a1, a2, a3);
set.start();
这里我们只是想要和用PropertyValuesHolder演示的动画一样,所以我们使用了playTogether()方法来进行控制动画同时进行,当然还可以使用别的方法,例如playSequentially(),with(),before(),after()等方法来控制多个动画的工作方式,从而做到对动画播放顺序的精确控制,这里的动画和上面的一样,就不放图片了
animate方法
Google在Android3.0以后,给View添加了一个animate方法来直接驱动属性动画,这可以认为是属性动画的简写形式,代码如下:
btn.animate()
.translationX(300)
.y(300)
.setDuration(1000)
.withStartAction(new Runnable() {
@Override
public void run() {
}
}).withEndAction(new Runnable() {
@Override
public void run() {
}
}
).start();
设置了两个动画,这里是同时进行的,还有两个回调方法,开始和结束
这样一来,简单的属性动画效果就都说完啦
最后
爱生活,爱小丽,爱Android