Android动画主要分为三类,帧动画、补间动画和属性动画
本篇博客一起来看属性动画
一、什么是属性动画
属性动画(Property Animation)是在Android3.0才推出的,并不像帧动画与补间动画一样很早就进入了江湖。那么后推出肯定是为了解决之前存在的某些问题,那么帧动画和补间动画存在什么问题呢?
帧动画和补间动画的局限性:
1)动画效果单一,可拓展性差
补间动画只能实现平移、旋转、缩放、透明度等一种或者多种动画的组合,如果遇到更复杂的动画需求,就会有点无力。
2)没有改变View的属性,只是改变视觉效果
再补间动画提到过,只是单纯的改变了View的视觉效果,而没有改变View的属性(上篇博客提到的点击事件的栗子)
3)作用目标单一
只能作用于View,而无法作用于View的属性
针对于这些需要优化的问题,便有了属性动画。可以作用于任意对象的任意属性,在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果
二、属性动画的使用
关于属性动画的使用,主要是两个动画类:ValueAnimator和ObjectAnimator,两个辅助类:
插值器(决定值的变化模式(匀加速、匀速等)) & 估值器(决定具体的变化数值)
1)ValueAnimator
通过不断控制值的变化,再不断手动的赋给对象的属性,从而实现动画效果。
--> 设置动画的运行时长、动画效果对应属性的初始值结束值等
--> 设置属性值从初始值过渡到结束值的变化逻辑 (ValueAnimator.ofInt()、ValueAnimator.ofFloat()、ValueAnimator.ofObject())
--> 根据上面的变化不断改变值
--> 值没改变一次,就手动赋值给对象的属性值一次
--> 每次赋值都调用invalidate()不断刷新视图
--> 不断循环上面两个步骤,直到结束
使用ValueAnimator,建议在Java代码中去写,更加灵活,举个栗子,这里用属性动画去改变Button的大小
// 步骤1:设置属性数值的初始值 & 结束值
ValueAnimator valueAnimator = ValueAnimator.ofInt(mButton.getLayoutParams().width, 400);
// 初始值 = 当前按钮的宽度,此处在xml文件中设置为200
// 结束值 = 400
// ValueAnimator.ofInt()内置了整型估值器,直接采用默认的.不需要设置
// 即默认设置了如何从初始值200过渡到 结束值400
// 步骤2:设置动画的播放各种属性
valueAnimator.setDuration(2000);
// 设置动画运行时长:1s
// 步骤3:将属性数值手动赋值给对象的属性:此处是将 值 赋给 按钮的宽度
// 设置更新监听器:即数值每次变化更新都会调用该方法
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
int currentValue = (Integer) animator.getAnimatedValue();
// 获得每次变化后的属性值
System.out.println(currentValue);
// 输出每次变化后的属性值进行查看
mButton.getLayoutParams().width = currentValue;
// 每次值变化时,将值手动赋值给对象的属性
// 即将每次变化后的值 赋 给按钮的宽度,这样就实现了按钮宽度属性的动态变化
// 步骤4:刷新视图,即重新绘制,从而实现动画效果
mButton.requestLayout();
}
});
valueAnimator.start();
// 启动动画
}
ValueAnimator.ofFloat的使用方式与ValueAnimator.ofInt一样,只不过是以浮点数的形式,将开始值过度到结束值;同理,ValueAnimator.ofObject是将初始值以对象的形式过渡到了结束值,例如这个对象可以是圆(封装了原点坐标和半径)、矩形(封装了长宽坐标)等。
在使用ValueAnimator.ofObject之前,我们需要先理解上面提到的估值器(TypeEvaluator)
看到这里可能小伙伴会有疑问,为什么在使用ValueAnimator.ofFloat和ValueAnimator.ofInt的时候,没有提到估值器呢?因为在这两个方法中,系统已经设置了两个默认的估值器IntEvaluator和FloatEvaluator,通过查看源码即可知
public static ValueAnimator ofFloat(float... values) {
ValueAnimator anim = new ValueAnimator();
anim.setFloatValues(values);
return anim;
}
ofFloat方法里调用了setFloatValues方法
public void setFloatValues(float... values) {
if (values == null || values.length == 0) {
return;
}
if (mValues == null || mValues.length == 0) {
setValues(PropertyValuesHolder.ofFloat("", values));
} else {
PropertyValuesHolder valuesHolder = mValues[0];
valuesHolder.setFloatValues(values);
}
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
在setFloatValues方法里查看到PropertyValuesHolder
// type evaluators for the primitive types handled by this implementation
private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
这里便有IntEvaluator和FloatEvaluator的具体实现
但是对于ObjectEvaluator,操纵的是对象,具有高度封装及个性化的特性,所有需要开发者自己去实现估值器,可以模仿FloatEvaluator或者IntEvaluator的写法,毕竟源码是最好的学习资料
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. 再加上初始值,就得到当前动画的值
}
}
看了FloatEvaluater的实现,我们自定义一个类也去实现TypeEvaluator
// 实现TypeEvaluator接口
public class ObjectEvaluator implements TypeEvaluator{
// 复写evaluate()
// 在evaluate()里写入对象动画过渡的逻辑
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
// 参数说明
// fraction:表示动画完成度(根据它来计算当前动画的值)
// startValue、endValue:动画的初始值和结束值
... // 写入对象动画过渡的逻辑
return value;
// 返回对象动画过渡的逻辑计算后的值
}
2)ObjectAnimator
通过不断控制值的变化,再不断自动的赋给对象的属性,从而实现动画效果。
--> 设置动画的运行时长、动画效果对应属性的初始值结束值等
--> 设置属性值从初始值过渡到结束值的变化逻辑
--> 根据上面的变化不断改变值
--> 值没改变一次,就自动赋值给对象的属性值一次
--> 每次赋值都调用invalidate()不断刷新视图
--> 不断循环上面两个步骤,直到结束
看完ObjectAnimator的定义,发现与ValueAnimator本质上一样,不同点则是ValueAnimator需要手动赋值,而ObjectAnimator是自动赋值。
三、总结
估值器与插值器
定义:
插值器:一个辅助动画实现的接口
插值器:一个辅助动画插值器的接口(属性动画特有)
作用:
估值器:设置属性值从初始值过度到结束值的变化规律(如匀速、先匀加速后匀减速等)
插值器:设置属性值从初始值过度到结束值的具体变化数值(插值器决定值的变化规律和趋势,而接下来具体的数值变化则交给估值器)
ValueAnimator:先改变值,然后手动赋值给对象的属性,从而实现动画(间接对对象属性进行操作)
ObjectAnimator:继承自ValueAnimator,先改变值,然后自动赋值给对象属性从而实现动画(直接对对象进行操作)