Android 中的属性动画 --- 2(插值器)

朱雀 2022-06-16 04:22 614阅读 0赞

在上篇文章中我们看了一下 Android 属性动画的基本用法,如果有兴趣的小伙伴可以看一下上一篇文章: Android 中的属性动画 — 1(基本用法)

在上一篇文章中,我们使用 ValueAnimator 这个类来实现了操作 View 对象的 height 属性从而实现了动画形式的显示和隐藏 View 控件。我们知道 ValueAnimator 这个类只用于根据当前动画的完成度和按照一定的“规律”产生一系列有规律的数字,事实上,属性动画的核心部分也就是这个,我们可以不断获取 ValueAnimator 产生的数字用于操作 View 的属性从而完成动画。那么 ValueAnimator 按照什么“规律”来产生一系列的数字呢?其实这个规律就是插值器。我们在定义属性动画的时候,需要通过setDuring 方法来为属性动画指定完成这个动画的时间,那么插值器就是用不同的时间因子产生不同的值,说白了插值器就像是一个公式,根据输入来转换成对应的输出。不同的插值器下,每个单位时间所达到的变化值也是不一样的,如果说使用线性插值器,那么每个单位时间内变化的值都一样。这就好比在规定的时间内跑步一样,有些人一开始跑的快,后面跑的慢,有些人一开始跑得慢,后面跑得快,但是大家都能在规定的时间里面到达终点。插值器就相当于描述跑步速度的对象。
Android 属性动画框架给我们提供了一些插值器和其对应的变化曲线:

1、AccelerateDecelerateInterpolator:

SouthEast

2、AccelerateInterpolator:

这里写图片描述

3、AnticipateInterpolator:

这里写图片描述

4、AnticipateOvershootInterpolator:

这里写图片描述

5、BounceInterpolator:

这里写图片描述

6、CycleInterpolator:

这里写图片描述

7、DecelerateInterpolator:

这里写图片描述

8、LinearInterpolator:

这里写图片描述

9、OvershootInterpolator:

这里写图片描述

那么问题来了,这么多类型的插值器,我们怎么去使用它们呢?其实很简单,属性动画对象有一个方法:objectAnimator.setInterpolator(TimeInterpolator value); 用于设置插值器,我们通过这个方法来设置插值器就行了。下面通过例子来具体看一下:

activity_main.xml:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. android:orientation="vertical"
  8. android:gravity="center_horizontal"
  9. tools:context="com.company.zhidian.androidobjectanimator.MainActivity">
  10. <Button
  11. android:id="@+id/startAnimatorTextView"
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"
  14. android:text="启动动画"/>
  15. </LinearLayout>

一个按钮的布局,下面是MainActivity.java:

  1. import android.animation.ObjectAnimator;
  2. import android.support.v7.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import android.view.animation.LinearInterpolator;
  6. import android.widget.Button;
  7. import android.widget.TextView;
  8. public class MainActivity extends AppCompatActivity {
  9. private TextView startAnimatorButton = null;
  10. @Override
  11. protected void onCreate(Bundle savedInstanceState) {
  12. super.onCreate(savedInstanceState);
  13. setContentView(R.layout.activity_main);
  14. startAnimatorButton = (Button) findViewById(R.id.startAnimatorTextView);
  15. startAnimatorButton.setOnClickListener(clickListener);
  16. }
  17. // 开始播放动画的方法
  18. private void startAnimator() {
  19. ObjectAnimator animator = ObjectAnimator.ofFloat(startAnimatorButton, "y", 0, 400);
  20. animator.setDuration(4000);
  21. // 设置动画的插值器为线性插值
  22. animator.setInterpolator(new LinearInterpolator());
  23. animator.start();
  24. }
  25. View.OnClickListener clickListener = new View.OnClickListener() {
  26. @Override
  27. public void onClick(final View view) {
  28. if(view == startAnimatorButton) {
  29. startAnimator();
  30. }
  31. }
  32. };
  33. }

单击事件为开始 startAnimator 方法,方法里面定义了一个属性动画,将这个按钮 y 方法从 0 移动到 400 px 的位置。因为设置的是线性插值器,so按钮在 y 轴上就是以一个固定的速度移动到 400 px 的位置:
这里写图片描述

那么我们换个插值器对象试试,只需更改 startAnimator 方法的一条代码:

  1. animator.setInterpolator(new OvershootInterpolator());

比较一下结果:

这里写图片描述

根据比较的结果和上面给出的图,我想小伙伴们应该能够理解插值器的作用了。对于其他 Android 提供给我们的插值器,小伙伴们可以自己尝试一下。

那么我们可以不可以不使用 Android 给我们直接提供的插值器而使用我们自己自定义的插值器呢?答案是肯定的。那么如何实现呢:
我们先看一下 Android 提供的线性插值器 LinearInterpolator 的实现代码:

  1. public class LinearInterpolator implements Interpolator {
  2. public LinearInterpolator() {
  3. }
  4. public LinearInterpolator(Context context, AttributeSet attrs) {
  5. }
  6. @Override
  7. public float getInterpolation(float input) {
  8. return input;
  9. }
  10. }

可以看到,自定义插值器的核心方法就是 getInterpolation 方法,在这个方法里面进行转换。getInterpolation 方法的参数是一个 0~1 之间的浮点数,它是描述动画完成进度的一个数字,这个参数的值会随着动画的运行而不断变化,根据设定的动画时长匀速增加。当动画一开始的时候input的值是0,然后不断匀速增加,直到到动画结束的时候input的值是1。线性插值器中直接把这个参数输出,我想也很好理解,因为线性插值本来就是以持续不变的速度执行的,所以并不需要转换。

那么,依葫芦画瓢,要自定义插值器,我们需要有一个类来实现 Interpolator 接口中的

  1. public float getInterpolation(float input);

方法,在这个方法里面我们需要将参数作为输入,通过转换得到我们想要的值并输出供实现动画使用。在这里有一个可以预览插值器效果的网站并且提供了一些插值器:http://inloop.github.io/interpolator/

这里写图片描述

里面有 Android 提供的插值器的曲线和对应的动画效果,我么这里就是用网站上提供的一个插值器并把它转化进入 Android 中使用,新建一个类,实现 Interpolator 接口:

  1. import android.view.animation.Interpolator;
  2. /**
  3. * Created by 指点 on 2017/5/5.
  4. */
  5. public class MyInterpolator implements Interpolator {
  6. private float CubicHermite(float t, float p0, float p1, float m0, float m1){
  7. float t2 = t*t;
  8. float t3 = t2*t;
  9. return (2*t3 - 3*t2 + 1)*p0 + (t3-2*t2+t)*m0 + (-2*t3+3*t2)*p1 + (t3-t2)*m1;
  10. }
  11. @Override
  12. public float getInterpolation(float input) {
  13. return CubicHermite(input, 0, 1, 4, 4);
  14. }
  15. }

同时修改 MainActivity.java 中的 startAnimator 方法:

  1. private void startAnimator() {
  2. ObjectAnimator animator = ObjectAnimator.ofFloat(startAnimatorButton, "y", 0, 400);
  3. animator.setDuration(4000);
  4. animator.setInterpolator(new MyInterpolator());
  5. animator.start();
  6. }

其实就是把插值器的类型换了一下。好了,来看看结果:

这里写图片描述

Ok,是不是感觉动画更加灵动一点。改成旋转动画试试,修改一下 startAnimator 方法中定义的的动画类型:

  1. ObjectAnimator animator = ObjectAnimator.ofFloat(startAnimatorButton, "rotation", 0, 360);

have a look:

这里写图片描述

看起来效果确实比直接变换好一点。当然,你也可以使用匿名类来在设置插值器的代码中直接自定义插值器,从而免去新建一个类的步骤。

好了,总结起来自定义插值器就是你可以通过自己琢磨出插值器公式或者去网上找一些公式然后转换成 Android 中的插值器作为你自己的插值器供实现属性动画使用。

如果博客中有什么不正确的地方,还请多多指点,如果觉得我写的不错,那么请点个赞支持我吧。

谢谢观看。。。

参考博客:http://blog.csdn.net/wingichoy/article/details/50667025

参考书籍:《Android 群英传》

发表评论

表情:
评论列表 (有 0 条评论,614人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Android属性动画

    一、属性动画出现的原因  属性动画(Property Animation)是在Android3.0(API  11)后才提供的一种全新的动画模式。 原因:由于补间和逐帧动画