在上一篇文章中,我们使用 ValueAnimator 这个类来实现了操作 View 对象的 height 属性从而实现了动画形式的显示和隐藏 View 控件。我们知道 ValueAnimator 这个类只用于根据当前动画的完成度和按照一定的“规律”产生一系列有规律的数字,事实上,属性动画的核心部分也就是这个,我们可以不断获取 ValueAnimator 产生的数字用于操作 View 的属性从而完成动画。那么 ValueAnimator 按照什么“规律”来产生一系列的数字呢?其实这个规律就是插值器。我们在定义属性动画的时候,需要通过setDuring 方法来为属性动画指定完成这个动画的时间,那么插值器就是用不同的时间因子产生不同的值,说白了插值器就像是一个公式,根据输入来转换成对应的输出。不同的插值器下,每个单位时间所达到的变化值也是不一样的,如果说使用线性插值器,那么每个单位时间内变化的值都一样。这就好比在规定的时间内跑步一样,有些人一开始跑的快,后面跑的慢,有些人一开始跑得慢,后面跑得快,但是大家都能在规定的时间里面到达终点。插值器就相当于描述跑步速度的对象。 Android 属性动画框架给我们提供了一些插值器和其对应的变化曲线:
1、AccelerateDecelerateInterpolator:
2、AccelerateInterpolator:
3、AnticipateInterpolator:
4、AnticipateOvershootInterpolator:
5、BounceInterpolator:
6、CycleInterpolator:
7、DecelerateInterpolator:
8、LinearInterpolator:
9、OvershootInterpolator:
那么问题来了,这么多类型的插值器,我们怎么去使用它们呢?其实很简单,属性动画对象有一个方法:objectAnimator.setInterpolator(TimeInterpolator value);
用于设置插值器,我们通过这个方法来设置插值器就行了。下面通过例子来具体看一下:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
tools:context="com.company.zhidian.androidobjectanimator.MainActivity">
<Button
android:id="@+id/startAnimatorTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动动画"/>
</LinearLayout>
一个按钮的布局,下面是MainActivity.java:
import android.animation.ObjectAnimator;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private TextView startAnimatorButton = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startAnimatorButton = (Button) findViewById(R.id.startAnimatorTextView);
startAnimatorButton.setOnClickListener(clickListener);
}
// 开始播放动画的方法
private void startAnimator() {
ObjectAnimator animator = ObjectAnimator.ofFloat(startAnimatorButton, "y", 0, 400);
animator.setDuration(4000);
// 设置动画的插值器为线性插值
animator.setInterpolator(new LinearInterpolator());
animator.start();
}
View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(final View view) {
if(view == startAnimatorButton) {
startAnimator();
}
}
};
}
单击事件为开始 startAnimator 方法,方法里面定义了一个属性动画,将这个按钮 y 方法从 0 移动到 400 px 的位置。因为设置的是线性插值器,so按钮在 y 轴上就是以一个固定的速度移动到 400 px 的位置:
那么我们换个插值器对象试试,只需更改 startAnimator 方法的一条代码:
animator.setInterpolator(new OvershootInterpolator());
比较一下结果:
根据比较的结果和上面给出的图,我想小伙伴们应该能够理解插值器的作用了。对于其他 Android 提供给我们的插值器,小伙伴们可以自己尝试一下。
那么我们可以不可以不使用 Android 给我们直接提供的插值器而使用我们自己自定义的插值器呢?答案是肯定的。那么如何实现呢: 我们先看一下 Android 提供的线性插值器 LinearInterpolator 的实现代码:
public class LinearInterpolator implements Interpolator {
public LinearInterpolator() {
}
public LinearInterpolator(Context context, AttributeSet attrs) {
}
@Override
public float getInterpolation(float input) {
return input;
}
}
可以看到,自定义插值器的核心方法就是 getInterpolation 方法,在这个方法里面进行转换。getInterpolation 方法的参数是一个 0~1 之间的浮点数,它是描述动画完成进度的一个数字,这个参数的值会随着动画的运行而不断变化,根据设定的动画时长匀速增加。当动画一开始的时候input的值是0,然后不断匀速增加,直到到动画结束的时候input的值是1。线性插值器中直接把这个参数输出,我想也很好理解,因为线性插值本来就是以持续不变的速度执行的,所以并不需要转换。
那么,依葫芦画瓢,要自定义插值器,我们需要有一个类来实现 Interpolator 接口中的
public float getInterpolation(float input);
方法,在这个方法里面我们需要将参数作为输入,通过转换得到我们想要的值并输出供实现动画使用。在这里有一个可以预览插值器效果的网站并且提供了一些插值器:http://inloop.github.io/interpolator/
里面有 Android 提供的插值器的曲线和对应的动画效果,我么这里就是用网站上提供的一个插值器并把它转化进入 Android 中使用,新建一个类,实现 Interpolator 接口:
import android.view.animation.Interpolator;
/**
* Created by 指点 on 2017/5/5.
*/
public class MyInterpolator implements Interpolator {
private float CubicHermite(float t, float p0, float p1, float m0, float m1){
float t2 = t*t;
float t3 = t2*t;
return (2*t3 - 3*t2 + 1)*p0 + (t3-2*t2+t)*m0 + (-2*t3+3*t2)*p1 + (t3-t2)*m1;
}
@Override
public float getInterpolation(float input) {
return CubicHermite(input, 0, 1, 4, 4);
}
}
同时修改 MainActivity.java 中的 startAnimator 方法:
private void startAnimator() {
ObjectAnimator animator = ObjectAnimator.ofFloat(startAnimatorButton, "y", 0, 400);
animator.setDuration(4000);
animator.setInterpolator(new MyInterpolator());
animator.start();
}
其实就是把插值器的类型换了一下。好了,来看看结果:
Ok,是不是感觉动画更加灵动一点。改成旋转动画试试,修改一下 startAnimator 方法中定义的的动画类型:
ObjectAnimator animator = ObjectAnimator.ofFloat(startAnimatorButton, "rotation", 0, 360);
have a look:
看起来效果确实比直接变换好一点。当然,你也可以使用匿名类来在设置插值器的代码中直接自定义插值器,从而免去新建一个类的步骤。
好了,总结起来自定义插值器就是你可以通过自己琢磨出插值器公式或者去网上找一些公式然后转换成 Android 中的插值器作为你自己的插值器供实现属性动画使用。
如果博客中有什么不正确的地方,还请多多指点,如果觉得我写的不错,那么请点个赞支持我吧。
谢谢观看。。。
参考博客:http://blog.csdn.net/wingichoy/article/details/50667025
参考书籍:《Android 群英传》
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有