视图(补间)动画的局限性
之前通过两篇文章介绍完了视图动画,其实从中我们也可以发现,补间动画只适用于简单的动画效果并且它完成的只是动画效果的展示,并没有能改变视图的属性,举个例子,一个按钮从(0,0)位移到(100,100),如果使用补间动画,会发现在当前位置(100,100)处点击按钮不能响应点击事件,说明按钮的位置属性并没有改变;再有,补间动画的组合效果也存在一定的局限性,无法实现动画的按序播放等;因此,为了解决和优化相关问题,Android又推出了属性动画。
属性(Animator)动画
一、概念
通过改变控件或视图的属性实现动画效果,属性值可以由开发者完全自定义。
二、特性
1、动画会改变视图的属性;
2、动画的形式可完全自定义,不再拘泥于平移、旋转等;
3、不同属性的变化不会互相影响,可以叠加使用;
4、通过AnimatorSet可以实现复合动画效果,且顺序可控;
三、相关核心类
四、控制过程
ValueAnimator是实现属性动画的核心类,通过设置视图属性的初始值、结束值以及控制过程中的属性值变化,达到动画的效果。
1、设置视图的初始值与结束值:
ofInt()和ofFloat()都只能用于对单一属性值变化的修改,以平移变化举例,上面两种方式只能实现对x或y单一属性的修改,如果想同时改变,则需要设置两个ValueAnimator,而如果使用ofObject,则可以自定义一个包含x,y的属性来实现同时改变x和y。
2、控制过程中的属性值:
对视图属性的控制,实际上就是控制视图什么时间点去设置什么样的属性值,并且作用到视图上;
void setInterpolator(TimeInterpolator value)就是通过设置时间插值器,来控制何时取值;
ofObject中的TypeEvaluator就是通过设置类型估值器,来设置当前时间点取多少属性值;
而addUpdateListener实现对属性值变化的监听,通过getAnimatedValue()拿到相应属性值,并对视图进行赋值;
后文会通过代码来具体说明,尤其是TimeInterpolator和TypeEvaluator;
3、其它的一些方法:
五、代码实现
OfInt与OfFloat用法相似,就以OfFloat为例,OfObject会在下一节举例;
1、通过Java方式实现:
//平移变换
translationAnimator = ValueAnimator.ofFloat(0,200,0);
//设置无限循环播放
translationAnimator.setRepeatCount(ValueAnimator.INFINITE);
//设置重复模式
translationAnimator.setRepeatMode(ValueAnimator.REVERSE);
//设置时间插值器,先加速后减速
translationAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
//设置动画时长
translationAnimator.setDuration(2000);
translationAnimator.addUpdateListener(animation -> {
float currentValue = (float) animation.getAnimatedValue();
imgAnim.setTranslationX(currentValue);
});
2、通过xml方式实现:
在res下新建animator目录,并新建xml文件value_anim:
<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:valueFrom="0"
android:valueTo="200"
android:valueType="floatType"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:repeatCount="-1"
android:repeatMode="reverse"/>
Animator animator = AnimatorInflater.loadAnimator(getApplicationContext(),R.animator.value_anim);
animator.start();
3、效果截图:
六、TimeInterpolator和TypeEvaluator
TimeInterpolator:通过设置时间流逝的百分率来反映、计算属性值的百分率;
以加速减速插值器(AccelerateDecelerateInterpolator)为例:
他的计算公式是:
那么通过函数图像来反映就是这样:
即先保持加速状态,快到1时加速开始变慢。Android原生为我们提供了不少时间插值器的模板,还有如线性插值器、弹性插值器、加速插值器等等,我们也可以根据需求自定义插值器。
TypeEvaluator:根据初始值(startValue)、最终值(endValue)以及初始值与最终值的比例关系(fraction,完成度),通过自定义的公式转换,得到每个时刻的变化属性值。TypeEvaluator的默认变化公式是贝塞尔曲线的线性变化公式。
如果现在需求是实现一段类似抛物线的动画,我们可以通过多阶贝塞尔曲线公式来实现,我们以二阶贝塞尔曲线为例,公式是:
其中B(t)就是返回的变化属性值,P0代表初始点,P1代表最终点,P2代表控制点(可以暂时理解为一个定点,控制点如何确定具体可看贝塞尔曲线的知识点),t代表的就是初始值与最终值的比例关系或者说完成度。
我们通过代码来看一下具体的实现:
1、定义一个Point类,用来表示点的坐标:
public class Point {
private float x;
private float y;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
}
2、定义TypeEvaulator:
Point controlP controlP = new Point(220, 40);//定义一个控制点
private class MyTypeEvaluator implements TypeEvaluator<Point> {
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
float x0 = startValue.getX();//起始点横坐标
float x1 = endValue.getX();//终点横坐标
float y0 = startValue.getY();//起点纵坐标
float y1 = endValue.getY();//终点纵坐标
float x = (float) (Math.pow((1 - fraction), 2) * x0 + 2 * fraction * (1 - fraction) * controlP.getX() + Math.pow(fraction, 2) * x1);
float y = (float) (Math.pow((1 - fraction), 2) * y0 + 2 * fraction * (1 - fraction) * controlP.getY() + Math.pow(fraction, 2) * y1);
Log.v("typeEvaluatorAnim", "x:" + x + ",fraction:" + fraction);
return new Point(x, y);
}
}
根据公式把相应参数代入,得到的x和y就是当前时刻的属性变化值;
3、配置动画:
//设置类型估值器并指定起点和终点
ValueAnimator typeEvaluatorAnim = ValueAnimator.ofObject(new MyTypeEvaluator(), new Point(0, 0),new Point(400, 400));
//设置时间插值器
typeEvaluatorAnim.setInterpolator(new LinearInterpolator());
//设置动画时长
typeEvaluatorAnim.setDuration(2000);
typeEvaluatorAnim.addUpdateListener(animation -> {
//获取时刻的属性变化值
Point point = (Point) animation.getAnimatedValue();
imgAnim.setTranslationX(point.getX());
imgAnim.setTranslationY(point.getY());
});
//开启动画
typeEvaluatorAnim.start();
4、效果截图:
5、总结
TimeInterpolator和都可以实现对过程中属性变化的控制,分别是通过修改时间的变化率和设置单位时间下的属性值变化来实现控制,在实际开发中,一般只需要对两者中的一个进行控制即可。
以上就是属性动画的初步总结,以后有时间还会继续研究,继续补充。