1 前言
属性动画(property animation)是Android3.0(API11)之后引入了新的动画特性。上篇介绍了Android系统中的View动画及帧动画,既然Android系统中已经有了这两种动画,那么可能会产生疑问为什么要引入属性动画?或者说是引入新的动画特性应该是为了解决View动画或帧动画的存在的哪些不足?Android官方文档对属性动画的详述点我
2 属性动画与View动画不同之处
回顾上篇文章,帧动画本质上也是View动画,View动画定义:是对View对象实现动画效果,支持平移、缩放、旋转和透明度这四种动画。那么View动画存在的不足主要体现在以下三个方面:
- 定义中着重强调了是对“View对象”实现动画,即它只能作用在具体的View上(比如:系统中提供的Button、ImageView以及任何继承View的自定义View),而无法非View对象实现动画效果。
- View动画只支持平移、缩放、旋转和透明度这四种动画,实现效果较单一,无法实现复杂的动画效果。例无法改变View的背景颜色。
- View动画支持的四种动画效果只是改变了View在视觉上的显示效果,而不会真正去改变View的属性。即假设把一个最初显示在左上角的ImageView通过View动画平移到右下角,此时ImageView的点击事件还是停留在左上角,点击右下角无响应。
属性动画其实也是为了弥补View动画的存在的缺陷而引入的一套全新动画模式。
3 属性动画使用详解
3.1 属性动画实现原理
属性动画要求动画作用的对象提供该属性的get和set方法,属性动画根据传递的该属性的初始值和最终值,以动画的效果多次去调用set方法,每次传递 给set方法的值都不一样,在动画结束时传递的就是最终值。 如果动画的时候没有提供初始值,那么该对应必须提供get方法,以便系统获取该属性的初始值。
3.2 相关属性与常用类
- Duration:动画的持续时间,默认300ms;
- TimeInterpolation:定义动画变化率的接口,如线性、非线性插值器;
- Repeat count and behavior:定义重复次数与重复模式,如播放n次或无限循环,重复时从头开始,还是反向;
- Frame refreash delay:定义动画每刷新一次的时间,默认为10ms,最终依赖系统的支持度;
- Animation sets:定义组合动画集合,可以同时执行或者顺序执行,下面具体介绍;
- TypeEvaluator 类型估值,主要用于设置动画操作属性的值。
- ObjectAnimator 动画的执行类,下面具体介绍;
- ValueAnimator 动画执行类,下面具体介绍。
3.3 ValueAnimator 实现动画
ValueAnimator 可以对指定一组整数、浮点数、颜色值等,根据动画执行的过程改变当前时间的所对应的取值。ValueAnimator主要有ofInt(),ofFloat(),或ofObject()、ofArgb()方法(API21以上)。
3.3.1 实现方式:java代码
ValueAnimator valueAnimator = ValueAnimator.ofInt(0,1);
//各种属性介绍
valueAnimator.setDuration(500); // 设置动画运行的时长
valueAnimator.setStartDelay(500); // 设置动画延迟播放时间
valueAnimator.setRepeatCount(0); // 设置动画重复播放次数 = 重放次数+1 , 设置为INFINITE时,动画无限重复
valueAnimator.setRepeatMode(ValueAnimator.RESTART);// 设置重复播放动画模式 ValueAnimator.RESTART(默认):正序重放 ValueAnimator.REVERSE:倒序回放
//设置 值的更新监听器
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.d("TAG", "current value is " + animation.getAnimatedValue());
}
});
valueAnimator.start();
使用就是so easy,但是不是发现,有点坑,ValueAnimator通过设置监听器可知,已经将一个将值从0过渡到1的,但如何作用到某个对象上来直观感受页面效果?其实这个就是ValueAnimator的一个优势,通过监听器监听值 的改变在onAnimationUpdate方法中可设置到任何对象的任何属性上。
演示一个通过ValueAnimator实现的动画效果,Button在Y轴平移的效果。
ValueAnimator valueAnimator = ValueAnimator.ofInt(300);
valueAnimator.addUpdateListener(new valueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentValue = (Integer) animation.getAnimatedValue();
Log.i("Tag","current value:"+animation.getAnimatedValue());
btn.setTranslationY(currentValue);
}
});
valueAnimator.start();
效果图:
举一反三,ValueAnimator中ofFloat()、ofArgb()与ofInt用法一致,只是在源码内部使用了不同的系统估计器,ofObject()需要传入一个Evaluator对象,关于Evaluator、Interpolators放在下篇介绍。
3.3.2 实现方式:XML文件
上节演示了在Java代码中实现属性动画,其实属性动画和补间动画一样,都可以在XML中编写。使用XML的一个优势是可以在多个页面重用,即更具重用性。
XML文件中一共有以下三种标签对应的动画类:
标签中也包含与上一篇介绍帧动画中常用属性:
duration 表示动画执行的时间
propertyName 表示修改的物件的哪个属性值,这里是透明度
valueFrom 表示从哪个状态值开始动画
valueTo 表示到哪个状态值结束动画
valueType 类型估值,主要用于设置动画操作属性的值
repeatMode 表示重复的模式 reverse表示
repeatCount 动画重复的计数,动画将会执行该值+1次
比如,要实现上节中button的在Y轴上平移效果,首先要在res下创建一个animator文件夹,创建anim_demo.xml文件输入以下内容
然后在代码中加载Xml文件
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_demo);
animator.setTarget(button);
animator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentValue = (Integer) animation.getAnimatedValue();
Log.i("Tag","current value:"+animation.getAnimatedValue());
btn.setTranslationY(currentValue);
}
});
animator.start();
3.4 ObjectAnimator 实现动画
ObjectAnimator是ValueAnimator的子类,也是属性动画中最常用使用的属性动画类,与ValueAnimator不同,ValueAnimator要在监听器的onAnimationUpdate方法中来操作具体对象的具体属性,而ObjectAnimator可以直接对传入的对象的属性进行动画操作。ObjectAnimator也有两种方式实现:
3.4.1实现方式:java代码
下面给出View动画的四种动画效果使用ObjectAnimator的java代码实现方式:
//平移动画
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btn,"translationY",0,100);
objectAnimator.setDuration(1000);
objectAnimator.start();
//旋转动画
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btn,"rotation",0,360);
objectAnimator.setDuration(1000);
objectAnimator.start();
//透明度动画
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btn,"alpha",1,0,1);
objectAnimator.setDuration(1000);
objectAnimator.start();
//缩放动画
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btn,"scaleY",1,3,1);
objectAnimator.setDuration(1000);
objectAnimator.start();
3.4.2 实现方式:XML文件
举一个缩放的XML文件方式实现,其它的动画只需要对propertyName进行改变,仿着写就ok了。
Java加载Xml文件
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.animator_scale);
anim.setTarget(button);
anim.start();
3.5 AnimatorSet 实现组合动画
实现组合动画功能要借助AnimatorSet类,主要包括以下四个方法:
after(Animator anim) 将现有动画插入到传入的动画之后执行
after(long delay) 将现有动画延迟指定毫秒后执行
before(Animator anim) 将现有动画插入到传入的动画之前执行
with(Animator anim) 将现有动画和传入的动画同时执行
比如说我们想要让button先旋转360度,然后平移到屏幕外,平移的同时进行淡入淡出操作,AnimatorSet也有两种方式实现:
3.5.1 实现方式:java代码
ObjectAnimator rotate = ObjectAnimator.ofFloat(btn, "rotation", 0f, 360f);
ObjectAnimator alpha = ObjectAnimator.ofFloat(btn, "alpha", 1f, 0f);
ObjectAnimator moveOut = ObjectAnimator.ofFloat(btn, "translationX", -500f);
AnimatorSet animSet = new AnimatorSet();
animSet.play(alpha).with(moveOut).after(rotate);
animSet.setDuration(3000);
animSet.start();
效果图:
3.5.2 实现方式:XML文件
代码码加载xml文件
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.anim_deom);
anim.setTarget(btn);
anim.start();
xml的实现效果与上节一样。
4监听器
3.3小节在介绍ValueAnimator时已经使用AnimatorUpdateListener来监听动画执行过程中的变化。那么如果要在某一个动画执行之前或者动画结束之后进行一些其他的操作,这个时候就要借助动画监听器Animator.AnimatorListener了。
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
//TODO 动画开始前的操作
}
@Override
public void onAnimationEnd(Animator animation) {
//TODO 动画结束的操作
}
@Override
public void onAnimationCancel(Animator animation) {
//TODO 动画取消的操作
}
@Override
public void onAnimationRepeat(Animator animation) {
//TODO 动画重复的操作
}
});
如果只要监听动画的某个或某几个事件,可以使用AnimatorListenerAdapter来简化上述代码。
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
//TODO 动画结束的操作
}
});
5 总结:
本篇主要初识一下属性动画ValueAnimator 、ObjectAnimator 、AnimatorSet的基本用法。后续会对属性动画进行进一步的学习。