Interpolator插值器学习

概述
简介
  • 定义:Android实现动画效果中的一个辅助接口
  • 作用:设置 属性值 从初始值过渡到结束值 的变化规律
  1. 如匀速、加速 & 减速 等等
  2. 即确定了 动画效果变化的模式,如匀速变化、加速变化 等等
应用场景

实现非线性运动的动画效果

非线性运动:动画改变的速率不是一成不变的,如加速 & 减速运动都属于非线性运动

具体使用

插值器在动画的使用有两种方式:在XML / Java代码中设置:

XML设置

前面多少都接触过了。

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"

android:interpolator="@android:anim/overshoot_interpolator"
// 通过资源ID设置插值器
android:duration="3000"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="2"
android:toYScale="2" />
>
Java设置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Button mButton = (Button) findViewById(R.id.Button);
// 步骤1:创建 需要设置动画的 视图View

Animation alphaAnimation = new AlphaAnimation(1,0);
// 步骤2:创建透明度动画的对象 & 设置动画效果

alphaAnimation.setDuration(3000);
Interpolator overshootInterpolator = new OvershootInterpolator();
// 步骤3:创建对应的插值器类对象

alphaAnimation.setInterpolator(overshootInterpolator);
// 步骤4:给动画设置插值器

mButton.startAnimation(alphaAnimation);
// 步骤5:播放动画
系统内置插值器
类型

Android系统内置了9种插值器

使用
  • 当在XML文件设置插值器时,只需传入对应的插值器资源ID即可
  • 当在Java代码设置插值器时,只需创建对应的插值器对象即可
  • 使用Android内置的插值器能满足大多数的动画需求
  • 系统默认的插值器是AccelerateDecelerateInterpolator,即先加速后减速
  • 如果上述9个插值器无法满足需求,还可以自定义插值器
自定义插值器
本质

根据动画的进度(0%-100%)计算出当前属性值改变的百分比

实现方式

自定义插值器需要实现 Interpolator / TimeInterpolator接口 & 复写getInterpolation()

  1. 补间动画 实现 Interpolator接口;属性动画实现TimeInterpolator接口
  2. TimeInterpolator接口是属性动画中新增的,用于兼容Interpolator接口,这使得所有过去的Interpolator实现类都可以直接在属性动画使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Interpolator接口
public interface Interpolator {

// 内部只有一个方法
float getInterpolation(float input) {
// 参数说明
// input值值变化范围是0-1,且随着动画进度(0% - 100% )均匀变化
// 即动画开始时,input值 = 0;动画结束时input = 1
// 而中间的值则是随着动画的进度(0% - 100%)在0到1之间均匀增加

...// 插值器的计算逻辑

return xxx;
// 返回的值就是用于估值器继续计算的fraction值,下面会详细说明
}

// TimeInterpolator接口
// 同上
public interface TimeInterpolator {

float getInterpolation(float input);

}

在学习自定义插值器前,我们先来看两个已经实现好的系统内置差值器:

  • 匀速插值器:LinearInterpolator
  • 先加速再减速 插值器:AccelerateDecelerateInterpolator
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
// 匀速差值器:LinearInterpolator
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
// 仅贴出关键代码
...
public float getInterpolation(float input) {
return input;
// 没有对input值进行任何逻辑处理,直接返回
// 即input值 = fraction值
// 因为input值是匀速增加的,因此fraction值也是匀速增加的,所以动画的运动情况也是匀速的,所以是匀速插值器
}


// 先加速再减速 差值器:AccelerateDecelerateInterpolator
@HasNativeInterpolator
public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
// 仅贴出关键代码
...
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
// input的运算逻辑如下:
// 使用了余弦函数,因input的取值范围是0到1,那么cos函数中的取值范围就是π到2π。
// 而cos(π)的结果是-1,cos(2π)的结果是1
// 所以该值除以2加上0.5后,getInterpolation()方法最终返回的结果值还是在0到1之间。只不过经过了余弦运算之后,最终的结果不再是匀速增加的了,而是经历了一个先加速后减速的过程
// 所以最终,fraction值 = 运算后的值 = 先加速后减速
// 所以该差值器是先加速再减速的
}
}
实例说明

实现一个 自定义 Interpolator : 先减速后加速

步骤1:根据需求实现 Interpolator 接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class DecelerateAccelerateInterpolator implements TimeInterpolator {

@Override
public float getInterpolation(float input) {
float result;
if (input <= 0.5) {
result = (float) (Math.sin(Math.PI * input)) / 2;
// 使用正弦函数来实现先减速后加速的功能,逻辑如下:
// 因为正弦函数初始弧度变化值非常大,刚好和余弦函数是相反的
// 随着弧度的增加,正弦函数的变化值也会逐渐变小,这样也就实现了减速的效果。
// 当弧度大于π/2之后,整个过程相反了过来,现在正弦函数的弧度变化值非常小,渐渐随着弧度继续增加,变化值越来越大,弧度到π时结束,这样从0过度到π,也就实现了先减速后加速的效果
} else {
result = (float) (2 - Math.sin(Math.PI * input)) / 2;
}
return result;
// 返回的result值 = 随着动画进度呈先减速后加速的变化趋势
}
}

步骤2: 设置使用

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
public class Demo_Interpolator extends AppCompatActivity {

private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo__interpolator);

button = findViewById(R.id.dec_accel);

//获得按钮的当前位置
float curTranslationX = button.getTranslationX();

ObjectAnimator animator = ObjectAnimator.ofFloat(button,"translationX",curTranslationX,500,curTranslationX);
// 创建动画对象 & 设置动画
// 表示的是:
// 动画作用对象是mButton
// 动画作用的对象的属性是X轴平移
// 动画效果是:从当前位置平移到 x=1500 再平移到初始位置

animator.setDuration(5000);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.start();
}
}

效果

与估值器区别

正余弦图像

md,差点连图像怎么画都忘了

sin(x):

cos(x):

Demo 地址

https://github.com/Commandercc/DemoEX/blob/master/AnimationDmeo3.zip

0%