属性动画

动画的种类

Android中的动画有视图动画(View)和属性动画(Property),其中视图动画还包括补间动画和逐帧动画,也就是我们常说的Frame动画和Tweened动画。
属性动画property是在Android3.0(API 11)之后才出现的,比视图动画出现的晚,显然也比较高级。视图动画能实现的效果,理论上属性动画也能实现,而且更加的灵活。

动画的区别

这里列举的区别主要是功能上的区别,也体现了两者的优缺点。

  1. 针对的对象:属性动画可以作用于任何对象,而补间动画只能作用于视图。即使没有对象,依然可以使用属性动画
  2. 动画效果:补间动画的效果只有:平移、旋转、缩放、透明度4种,而属性动画还可在此基础上进行拓展。
  3. 作用对象的属性:补间动画只改变了视图的效果,并不能改变View的属性。也就是说当你利用补间动画让一个按钮Button从A点移动到B点后,你再点击A点,同样存在点击效果的。而属性动画则是实实在在的改变了按钮的位置。这个在自定义View中的使用十分常见。

动作原理

在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性(补间动画不会改变对象的属性),从而实现该对象在该属性上的动画效果。

  1. 赋值:动画时长、开始值、结束值
  2. 值变化:从开始值到结束值的过渡
  3. 值每改变一次,就对对象的属性赋值一次,直到开始值等于结束值
  4. 每次赋值都会调用invalidate()不断的刷新视图,利用onDraw()绘制视图。从而实现动画效果

使用

属性动画有两个非常重要的类:ValueAnimator 类 和 ObjectAnimator 类。
两者的区别就是在赋值的时候,ValueAnimator是手动赋值,ObjectAnimator是自动赋值的

ValueAnimator

有三个重要方法:
ValueAnimator.ofInt(int values):将初始值 以整型数值的形式 过渡到结束值
ValueAnimator.ofFloat(float values):将初始值 以浮点型数值的形式 过渡到结束值
ValueAnimator.ofObject(int values):将初始值 以对象的形式 过渡到结束值,面向对象操作的,需要自定义对象类
下面针对ofInt作演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// 步骤1:设置动画属性的初始值 & 结束值
ValueAnimator anim = ValueAnimator.ofInt(0, 3);
// ofInt()作用有两个
// 1. 创建动画实例
// 2. 将传入的多个Int参数进行平滑过渡:此处传入0和1,表示将值从0平滑过渡到1
// 如果传入了3个Int参数 a,b,c ,则是先从a平滑过渡到b,再从b平滑过渡到C,以此类推
// ValueAnimator.ofInt()内置了整型估值器,直接采用默认的.不需要设置,即默认设置了如何从初始值 过渡到 结束值
// 关于自定义插值器我将在下节进行讲解
// 下面看看ofInt()的源码分析 ->>关注1
// 步骤2:设置动画的播放各种属性
anim.setDuration(500);
// 设置动画运行的时长
anim.setStartDelay(500);
// 设置动画延迟播放时间
anim.setRepeatCount(0);
// 设置动画重复播放次数 = 重放次数+1
// 动画播放次数 = infinite时,动画无限重复
anim.setRepeatMode(ValueAnimator.RESTART);
// 设置重复播放动画模式
// ValueAnimator.RESTART(默认):正序重放
// ValueAnimator.REVERSE:倒序回放
// 步骤3:将改变的值手动赋值给对象的属性值:通过动画的更新监听器
// 设置 值的更新监听器
// 即:值每次改变、变化一次,该方法就会被调用一次
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentValue = (Integer) animation.getAnimatedValue();
// 获得改变后的值
System.out.println(currentValue);
// 输出改变后的值
// 步骤4:将改变后的值赋给对象的属性值,下面会详细说明
View.setproperty(currentValue);
// 步骤5:刷新视图,即重新绘制,从而实现动画效果
View.requestLayout();
}
});
anim.start();
// 启动动画
}
public static ValueAnimator ofInt(int... values) {
// 允许传入一个或多个Int参数
// 1. 输入一个的情况(如a):从0过渡到a;
// 2. 输入多个的情况(如a,b,c):先从a平滑过渡到b,再从b平滑过渡到C
ValueAnimator anim = new ValueAnimator();
// 创建动画对象
anim.setIntValues(values);
// 将传入的值赋值给动画对象
return anim;
}

上面是Java代码演示,也可以在XML中(set_animation.xml)设置动画:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ValueAnimator采用<animator> 标签
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="0" // 初始值
android:valueTo="100" // 结束值
android:valueType="intType" // 变化值类型 :floatType & intType
android:duration="3000" // 动画持续时间(ms),必须设置,动画才有效果
android:startOffset ="1000" // 动画延迟开始时间(ms
android:fillBefore = “true” // 动画播放完后,视图是否会停留在动画开始的状态,默认为true
android:fillAfter = “false” // 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
android:fillEnabled= “true” // 是否应用fillBefore值,对fillAfter值无影响,默认为true
android:repeatMode= “restart” // 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart|
android:repeatCount = “0” // 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
android:interpolator = @[package:]anim/interpolator_resource // 插值器,即影响动画的播放速度,下面会详细讲
/>

然后在Java中添加进去:

1
2
3
4
5
6
7
8
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.set_animation);
// 载入XML动画
animator.setTarget(view);
// 设置动画对象
animator.start();
// 启动动画

ObjectAnimator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String property, float ....values);
// ofFloat()作用有两个
// 1. 创建动画实例
// 2. 参数设置:参数说明如下
// Object object:需要操作的对象
// String property:需要操作的对象的属性
// float ....values:动画初始值 & 结束值(不固定长度)
// 若是两个参数a,b,则动画效果则是从属性的a值到b值
// 若是三个参数a,b,c,则则动画效果则是从属性的a值到b值再到c值
// 以此类推
anim.setDuration(500);
// 设置动画运行的时长
anim.setStartDelay(500);
// 设置动画延迟播放时间
anim.setRepeatCount(0);
// 设置动画重复播放次数 = 重放次数+1
// 动画播放次数 = infinite时,动画无限重复
anim.setRepeatMode(ValueAnimator.RESTART);
// 设置重复播放动画模式
// ValueAnimator.RESTART(默认):正序重放
// ValueAnimator.REVERSE:倒序回放
animator.start();
// 启动动画

例如改变一个按钮的透明度属性:

1
2
3
4
5
6
7
8
9
10
mButton = (Button) findViewById(R.id.Button);
// 创建动画作用对象:此处以Button为例
ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, "alpha", 1f, 0f, 1f);
// 表示的是:
// 动画作用对象是mButton
// 动画作用的对象的属性是透明度alpha
// 动画效果是:常规 - 全透明 - 常规
animator.setDuration(5000);
animator.start();

可以明显看出,相对于ValueAnimator,ObjectAnimator是不需要手动赋值。
其同样可以在XML文件中表示出以上的效果:

1
2
3
4
5
6
7
8
// ObjectAnimator 采用<animator> 标签
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="1" // 初始值
android:valueTo="0" // 结束值
android:valueType="floatType" // 变化值类型 :floatType & intType
android:propertyName="alpha" // 对象变化的属性名称
/>

然后在Java中启动

1
2
3
4
5
6
7
8
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.view_animation);
// 载入XML动画
animator.setTarget(view);
// 设置动画对象
animator.start();
// 启动动画

TypeEvaluator与Interpolator

  1. 插值器(Interpolator)决定 值 的变化模式(匀速、加速、减速)
  2. 估值器(TypeEvaluator)决定 值 的具体变化数值

例如一个自由落体运动,物体是由静止慢慢加速掉落的,插值器(Interpolator)可以让这种效果更加明显、形象。而估值器(TypeEvaluator)体现了初始值与结束值以浮点型的过渡的逻辑。
例如FloatEvaluator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class FloatEvaluator implements TypeEvaluator {
// FloatEvaluator实现了TypeEvaluator接口
// 重写evaluate()
public Object evaluate(float fraction, Object startValue, Object endValue) {
// 参数说明
// fraction:表示动画完成度(根据它来计算当前动画的值)
// startValue、endValue:动画的初始值和结束值
float startFloat = ((Number) startValue).floatValue();
return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
// 初始值 过渡 到结束值 的算法是:
// 1. 用结束值减去初始值,算出它们之间的差值
// 2. 用上述差值乘以fraction系数
// 3. 再加上初始值,就得到当前动画的值
}
}

组合动画

实现 组合动画 的功能:AnimatorSet类
AnimatorSet.play(Animator anim) :播放当前动画
AnimatorSet.after(long delay) :将现有动画延迟x毫秒后执行
AnimatorSet.with(Animator anim) :将现有动画和传入的动画同时执行
AnimatorSet.after(Animator anim) :将现有动画插入到传入的动画之后执行
AnimatorSet.before(Animator anim) : 将现有动画插入到传入的动画之前执行

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 步骤1:设置需要组合的动画效果
ObjectAnimator translation = ObjectAnimator.ofFloat(mButton, "translationX", curTranslationX, 300,curTranslationX);
// 平移动画
ObjectAnimator rotate = ObjectAnimator.ofFloat(mButton, "rotation", 0f, 360f);
// 旋转动画
ObjectAnimator alpha = ObjectAnimator.ofFloat(mButton, "alpha", 1f, 0f, 1f);
// 透明度动画
// 步骤2:创建组合动画的对象
AnimatorSet animSet = new AnimatorSet();
// 步骤3:根据需求组合动画
animSet.play(translation).with(rotate).before(alpha);
animSet.setDuration(5000);
// 步骤4:启动动画
animSet.start();

效果:

总结

属性动画的本质原理:通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果。
其中涉及的类及其功能如下图:

------ 本文结束 ------

版权声明

文章作者: 周 康

发布时间: 2017年06月25日 - 00:06

原始链接: http://Kanging.github.io/2017/06/25/属性动画/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。