目录
一、简介
属性动画的一种,顾名思义通过值来实现动画。
对指定的数字范围进行动画运算,需要做的便是对数字更新变化过程进行监听(animator.addUpdateListener()),对控件做出对应的动画操作。
更多方法见https://developer.android.com/reference/android/animation/ValueAnimator
优势:
1.可以实现补间动画不能实现的功能
2.作用对象不再局限于view,而视图动画仅提供view对象的动画(ofObject)
3.改变的是控件的属性,而补间动画仅能作出动画效果
二、差值器和估值器
用来设置动画“动”的方式,匀速、加速还是先加速再减等等,都可以通过这两个来实现。
1、差值器
添加方式:
animator.setInterpolator(new LinearInterpolator());
其中LinearInterpolator()便为一个差值器。
系统实现了默认的几个:
一般情况下是够用的
自定义差值器:
特殊情况下,需要自己实现,既然系统有给出的,那就是最好的学习样例,先看最简单的线性差值器
继承了BaseInterPolator,而BaseInterPolator实现了Interpolator接口,Interpolator接口直接继承自TimeInterpolator
仅有一个方法,而要实现自定义的差值器,关键即在这个方法
输入是一个float值,其取值范围为0~1,输出也是一个取值范围为0~1的float,知道他俩分别代表的意义便可以自己实现一个炫酷差值器。
首先,输入input,指的是当前时间的一个进度,即开始设置的animator.setDuration(500);这个500的一个进度,可以将其看成一个函数里的自变量;
其次,输出,指的是当前值的一个进度,即开始设置的animator.setFloatValues(startNum, endNum);从startNum变到endNum的一个进度,他是因变量。
在我看来,getInterPolator方法便是做了一个他俩的映射,通过控制他俩的映射方式来控制动画的改变速度。
比如,上面的LinearInterpolator,他俩的映射便如下图:
即动画随着时间的推移匀速变化
再比如:
public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolator {
...
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
...
}
映射如下:
通过指数函数来实现刚开始速度较慢,之后速度越来越快的加速运动
其他的差值器:
Android动画插值器 - Gityuan博客 | 袁辉辉的技术博客
将时间与值的映射,转换为他俩对应进度的映射,高!!!
所以,要自定义一个差值器,仅需要实现TimeInterceptor接口,并实现getInterpolation方法来实现一个映射。
2、估值器
在拿到值的一个进度之后,便需要将进度映射为具体的值,估值器做的便是这件事儿。
添加方式:
animator.setEvaluator(new IntEvaluator());
其中IntEvaluator()为一个估值器。
系统默认实现:
自定义估值器:
同样,可以通过系统默认实现来学习,下面为计算int属性的估值器:
可以看出,可以通过实现TypeEvaluator<Integer>接口,并实现evaluate方法,而evaluate方法的实现也很简单。
evaluate方法便是进度到具体值的映射
fraction为差值器返回的目前的值进度
startValue和endValue分别为值的起始值和终值
要实现一个自定义估值器,就实现这个方法来将当前进度映射为具体值
三、ofObject
ofInt、ofFloat以及ofArgb都是针对对应的对象,如果需要操作一个其他的对象,就需要用到ofObject
例如要实现一个大写字母A到Z的动画:
//通过ofObject新建ValueAnimator,需要注意两点
//1.传入的参数第一个为一个估值器,针对需要操作的对象需要实现对应的估值器
//2.之后的是一系列object,即需要操作的对象
ValueAnimator animator = ValueAnimator.ofObject(new CharEvaluator(),new Character('A'),new Character('Z'));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
char text = (char)animation.getAnimatedValue();
tv.setText(String.valueOf(text));
}
});
animator.setDuration(10000);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
对应的估值器:
public class CharEvaluator implements TypeEvaluator<Character> {
@Override
public Character evaluate(float fraction, Character startValue, Character endValue) {
//根据的是字母的ASCII码,(A~Z => 65~90)
int startInt = (int)startValue;
int endInt = (int)endValue;
int curInt = (int)(startInt + fraction *(endInt - startInt));
char result = (char)curInt;
return result;
}
}
四、动画流程
即start之后发生了什么:
1.ValueAnimator(public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback):
addAnimationCallback(0); --->
getAnimationHandler().addAnimationFrameCallback(this, delay);
2.AnimationHandler:
之后会回调:
处理这一帧中所有的动画
3.ValueAnimator:
ValueAnimator实现了AnimationFrameCallback接口
真正处理这一帧(animateBasedOnTime(currentTime))
animateBasedOnTime方法根据currentTime计算了fraction,然后调用animateValue
mValues是一个PropertyValuesHolder类的数组
4.PropertyValuesHolder:
PropertyValuesHolder这个类的意义就是保存动画过程中所需要操作的属性和对应的值。正常的操作是上面的数组大小为1,我目前看的是,当设置了.ofPropertyValuesHolder()多个PropertyValueHolder那个size才会大于1。
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start();
后期的对属性值的操作都在PropertyValuesHolder进行
![](https://img-blog.csdnimg.cn/img_convert/8554651512e4ec61a479aa68bcb7b107.png)
4.KeyframeSet
两个关键帧时,根据差值器(俩关键帧之间设置的插值器)获取fraction,然后根据估值器获得对应的值。
五、补充问题
1.关键帧概念?
Keyframe 对象由 时间、值 对组成,用于在动画的特定时间定义特定的状态。
2.任意两个关键帧间是否可以设置差值器?
每个关键帧可以用自己的插值器控制动画在上一关键帧时间和此关键帧时间之间的时间间隔内的行为。用这个方法设置差值器:
android.animation.Keyframe#setInterpolator
如果animator的插值器和keyframe的关键帧都设置了,会叠加计算,我感觉算出来是个啥结果比较难以确定animator的插值器 调用位置
keyframe的关键帧设置的插值器调用位置,这个输入是上一个方法得到的animator的插值器计算后的fraction
![](https://img-blog.csdnimg.cn/img_convert/a3cbd1f39669ff1d6258c7cd6f82b546.png)
3.NativeInterpolator是啥
这个还真没查到,下面是源码,说是一个native差值器,用来硬件加速渲染的?
![](https://img-blog.csdnimg.cn/img_convert/6710b9baa2e6fda10436a04a483fbc29.png)
4.android.animation.KeyframeSet#getValue 的 fraction小于0?
有可能小于0的,因为这个fraction是经过插值器计算之后的值的进度,可能出现负数,比如AnticipateInterpolator()
5.fraction小于0,为啥关键帧是get(1)
关键帧的插值器计算的是上一帧到本帧的过程,因此第一帧差值器应该为无效,这块应该get(1)
6.动画的种类,选择
帧动画:将动画拆成一帧一帧的,需要具体定义好每一帧
优点:使用简单,最简单最直观的动画
缺点:如果使用大量大图容易造成oom
(看到项目里的使用都是小图的使用场景,而且使用也不多)
补间动画:确定动画的开始和结束值,中间由系统补全,系统提供了四种动画方式透明度(AlphaAnimation),缩放(ScaleAnimation),旋转(RotateAnimation),位移(TranslateAnimation)
优点:使用简单
缺点:作用的不是控件的属性,视觉上的效果,并没有真正改变控件,控件还是原来的状态;而且功能有限,动画效果单一;作用对象局限于view
(用来对控件进行透明度、缩放、旋转、位移的操作;还有activity以及fragment的切换动画等;)
属性动画:通过不断改变控件的属性来产生动画效果
优点:1.可以实现补间动画不能实现的功能
2.作用对象不再局限于view,而视图动画仅提供view对象的动画(ofObject)
3.改变的是控件的属性,而补间动画仅能作出动画效果
缺点:可能对界面的性能有一定影响
(功能强大,使用场景广泛。我认为在补间动画无法完成的情况下使用这个更好)
六、相关网站:
差值器在线查看效果:
easings 是一个开源的插值器算法网站,涵盖了各种各样的插值器算法,绝大部分的物理场景都能找到:
插值器和估值器:
参考:
动画详解
https://wiki.jikexueyuan.com/project/android-animation/4.html