一、 属性动画引入的背景
1、view动画的不足之处
1、作用的对象只能是view
2、只能播放view的四种动画或动画组合(透明渐变、平移、缩放、旋转)
3、非view对象不能使用view动画
4、太局限 灵活性差
5、补间动画还有一个致命的缺陷,就是它只是改变了View的显示效果而已,而不会真正去改变View的属性。(这点可以给按钮设置点击事件进行平移动画测试点击位置)
2、属性动画
属性动画机制已经不再是针对于View来设计的了。它实际上是一种不断地对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性。我们只需要告诉系统动画的运行时长,需要执行哪种类型的动画,以及动画的初始值和结束值,剩下的工作就可以全部交给系统去完成了。
3、几个常用的类
- Animator 属性动画基类
- ValueAnimator 值动画
- ObjectAnimator 对象动画
- AnimatorSet 属性动画集合
4、几个类之间关系
(1)动画基类Animator :
属性动画基类
(2)关系类图
二、属性动画
1、ValueAnimator
(1)ValueAnimator简介
由于Animator是抽象类,ValueAnimator 是直接继承 Animator的。ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等(Animator的这些方法都在ValueAnimator 实现),确实是一个非常重要的类。所以ValueAnimator 是整个属性动画机制当中最核心的一个类。
(2)属性动画工作机制
属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。
(3)ValueAnimator 的使用
通过上文我们了解 属性动画可以作用于任何对象,其实也可以不作用对象而直接播放动画(如下栗子)
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f);
valueAnimator.setDuration(400);
valueAnimator.start();
// 这样就开启了一个简单的动画,表示吧一个值从0变化到1,执行时长300ms。
不作用与对象也可以播放动画?哇真的很强大,可是不作用对象我们运行代码怎没看到?怎没确定动画播放了?我们可以设置动画监听啊!!!栗子如下:
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f);
valueAnimator.setDuration(400);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
Log.i("blabla", "onAnimationUpdate: " + value);
}
});
valueAnimator.start();
// log 如下,可以看到数值从0到1平滑的改变。
2019-06-11 10:38:15.289 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.0
2019-06-11 10:38:15.331 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.0
2019-06-11 10:38:15.505 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.36806342
2019-06-11 10:38:15.608 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.7477293
2019-06-11 10:38:15.642 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.8535534
2019-06-11 10:38:15.650 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.89507747
2019-06-11 10:38:15.703 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.9822787
2019-06-11 10:38:15.716 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 0.99554986
2019-06-11 10:38:15.730 25924-25924/com.example.myapplication I/blabla: onAnimationUpdate: 1.0
ofFloat方法:
* @param values A set of values that the animation will animate between over time.
* @return A ValueAnimator object that is set up to animate between the given values.
*/
public static ValueAnimator ofFloat(float... values) {
ValueAnimator anim = new ValueAnimator();
anim.setFloatValues(values);
return anim;
}
这个方法表示改变的值为float类型。参数为可变参数,代表值在这些参数内变化。如上我们设置0-1代表300ms内从0变化到1。假如我们设置0,1,3。数值将0变化到1再变化到3。
ofInt方法:
和ofFloat类似,只是数值为int类型而不是小数类型。也是比较常用的方法
ofObject方法:
ObjectAnimator 中用的多,在ObjectAnimator 使用中再总结。
其他方法:
- setStartDelay 设置动画延迟播放时间
- setRepeatCount 设置动画循环次数
- setRepeatMode 设置动画循环播放模式(RESTART:重新播放,REVERSE:倒序播放)
2、ObjectAnimator
(1)ValueAnimator 的特点
1、对值操作
2、值平滑的发生变化
3、平时使用场景不多
(2)ObjectAnimator特点
1、对对象的属性进行操作
2、相比于ValueAnimator,ObjectAnimator可能才是我们最常接触到的类
3、它其实是继承自ValueAnimator的,底层的动画实现机制也是基于ValueAnimator来完成的
方法ofFloat
* @param target The object whose property is to be animated. This object should
* @param propertyName The name of the property being animated.
* @param values A set of values that the animation will animate between over time.
* @return An ObjectAnimator object that is set up to animate between the given values.
*/
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setFloatValues(values);
return anim;
}
和ValueAnimator 的ofFloat类似,有点小改动。
1、Object target 要操作的对象,对哪个对象进行动画。
2、String propertyName 要操作对象的属性,对哪个对象的属性进行动画。
3、 float… values 可变参数(值变化范围,这点和ValueAnimator 的ofFloat的参数一样)
简单例子如下:
button = findViewById(R.id.btn);
// 参数1: object 对象
// 参数2: 操作的属性 (属性要有get set方法)
// 3-n : 可变参数 要执行动画的数值变化范围
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(button, "rotation", 0f, 360f);
objectAnimator.setDuration(5000);
objectAnimator.start();
动画效果:按钮旋转360度
有了旋转rotation,其实我们也可以设置属性为:
- alpha(透明度变化)
- translationX(x轴方向平移)
- translationY(y轴方向平移)
- scaleY
- scaleX
- 等等
或许我们疑问:ObjectAnimator的ofFloat的第二个参数可以为那些属性值?上面我们知道可以传alpha、translationX、translationY、scaleY、scaleX等等。其实我们可以传入任意的值到ofFloat()方法的第二个参数当中。但事实就是如此。因为ObjectAnimator在设计的时候就没有针对于View来进行设计,而是针对于任意对象的,它所负责的工作就是不断地向某个对象中的某个属性进行赋值,然后对象根据属性值的改变再来决定如何展现出来。
(3)上述按钮动画栗子分析
1、其实这段代码的意思就是ObjectAnimator会帮我们不断地改变Button对象中rotation属性的值,从0f变化到360f。然后button对象需要根据rotation属性值的改变来不断刷新界面的显示,从而让用户可以看出旋转的动画效果。
2、那么button对象中是不是有rotation属性这个值呢?没有,不仅button没有这个属性,连它所有的父类也是没有这个属性的!这就奇怪了,button当中并没有rotation这个属性,ObjectAnimator是如何进行操作的呢?其实ObjectAnimator内部的工作机制并不是直接对我们传入的属性名进行操作的,而是会去寻找这个属性名对应的get和set方法,因此rotation属性所对应的get和set方法应该就是(如下代码)
3、那么button对象中是否有这两个方法呢?确实有,并且这两个方法是由View对象提供的,也就是说不仅button可以使用这个属性来进行淡入淡出动画操作,任何继承自View的对象都可以的。
4、既然rotation 可以那么我们上述说的alpha等等都可以了
ps:对象要有get set方法才能进行属性动画
public void setRotation(float value);
public float getRotation();
3、AnimatorSet-属性动画集合
(1)控制动画播放顺序的api
- after(Animator anim) 将现有动画插入到传入的动画之后执行
- after(long delay) 将现有动画延迟指定毫秒后执行
- before(Animator anim) 将现有动画插入到传入的动画之前执行
- with(Animator anim) 将现有动画和传入的动画同时执行
这几个api的返回值都是AnimatorSet.Builder类型实例,builder模式链式调用(如下play的源码)
//AnimatorSet的方法
public Builder play(Animator anim) {
if (anim != null) {
return new Builder(anim);
}
return null;
}
(2)栗子
// 旋转
ObjectAnimator rotation = ObjectAnimator.ofFloat(button, "rotation", 0f, 360f);
// 平移
float translationX = button.getTranslationX();
ObjectAnimator translation = ObjectAnimator.ofFloat(button, "translationX", translationX, -500f, translationX);
// 透明
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(button, "alpha", 1f, 0f, 1f);
// 动画集合播放上述动画
AnimatorSet animatorSet = new AnimatorSet();
// 先播放 translation 再同时播放rotation、fadeInOut
animatorSet.play(rotation).with(fadeInOut).after(translation);
animatorSet.setDuration(3000);
animatorSet.start();
(4)Animator监听器
动画怎没能没有监听呢?所以Animator提供了监听方法addListener(AnimatorListener listener),我们只需要实现这个listener就行啦。。。。。由于这方法是Animator提供所以属性动画通用。
- AnimatorListener
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
Log.i("blabla", "onAnimationStart: ");
}
@Override
public void onAnimationEnd(Animator animation) {
Log.i("blabla", "onAnimationEnd: ");
}
@Override
public void onAnimationCancel(Animator animation) {
Log.i("blabla", "onAnimationCancel: ");
}
@Override
public void onAnimationRepeat(Animator animation) {
Log.i("blabla", "onAnimationRepeat: ");
}
});
- AnimatorListenerAdapter
如上AnimatorListener使用时需要重写四个方法但是有时候我们可能不需要重写这么多,有时我们可能只需要重写一个,这时Android提供了一个适配器类,叫作AnimatorListenerAdapter,使用这个类就可以解决掉实现接口繁琐的问题了。(栗子如下)
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.addListener(new AnimatorListenerAdapter() {
// 重写想使用的方法即可
@Override
public void onAnimationStart(Animator animation) {
// todo
}
});
三、属性动画的xml实现
我们可以使用代码来编写所有的动画功能,这也是最常用的一种做法。不过,过去的补间动画除了使用代码编写之外也是可以使用XML编写的,因此属性动画也提供了这一功能,即通过XML来完成和代码一样的属性动画功能。
1、xml编写的优缺点
优点:
代码重用方便
缺点:
编写相对java代码麻烦
扩展性不高(比如动态获得手机信息就需要java代码实现)
2、标签
- animator 对应代码中的ValueAnimator
- objectAnimator 对应代码中的ObjectAnimator
- set 对应代码中的AnimatorSet
3、编写步骤
首先要在res目录下面新建一个animator文件夹
4、栗子
(1)从0到100平滑过渡的动画
<animator android:duration="3000"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"/>
(2)将一个视图的alpha属性从1变成0
<objectAnimator
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"
android:propertyName="alpha"/>
(3)组合动画
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<animator
android:duration="3000"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
<objectAnimator
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"
android:propertyName="alpha"/>
</set>
5、 xml动画资源加载
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.test);
animator.setTarget(button);
animator.start();
end
参考:
1、安卓开发艺术探索
2、
属性动画中级用法