插值器是一种函数(在数学意义上),可输出在作为输入提供给它的一系列值之间的“插值”值。插值只是在两个固定数据点之间生成新数据点的一种方法。这些生成的数据点的确切值由执行插值的类型确定。例如,在线性插值中,所有生成的值均匀分布在固定点之间。虽然了解插值是有帮助的,但不必开始为应用程序中的视图设置动画。实际上,插值的动画角度可能有助于理解它!因此,让我们开始吧。在此示例中,我们将创建一个带有按钮列表的简单应用程序。这些按钮中的每个按钮均用于特定类型的插值动画,当您按下该按钮时,该动画将开始。动画是一个简单的水平平移,可将按钮向右移动。
内插器接口
在Android开发框架中,Interpolator被定义为接口。这允许方法接受可以带入自己的配置的内插器,而不必将开发人员绑定到特定的实现。在撰写本文时,Interpolator接口有11个间接子类。他们是:
- 线性插值器:在两个固定点之间生成的值均匀分布。例如,将a = 1和b = 5作为不动点。 a和b之间的线性插值如下所示:1-> 2-> 3-> 4-> 5,其中已生成1和5之间的数字。
- 加速插值器:此插值器生成的值最初在它们之间具有很小的差异,然后逐渐增大差异,直到达到终点为止。例如,通过加速插值在1-> 5之间生成的值可能是1-> 1.2-> 1.5-> 1.9-> 2.4-> 3.0-> 3.6-> 4.3->5。请注意连续值之间的差异如何增大始终如一。
- 减速插值器:从某种意义上讲,加速插值器会以加速的方式生成值,当您在生成的值列表中前进时,减速插值器会生成“减速”的值。因此,最初生成的值在它们之间具有更大的差异,并且差异逐渐减小,直到达到终点为止。因此,在1-> 5之间生成的值看起来像是1-> 1.8-> 2.5-> 3.1-> 3.6-> 4.0-> 4.3-> 4.5-> 4.6-> 4.7-> 4.8-> 4.9-> 5再次,注意连续值之间的差异变小。
- 加速减速插补器:此插补器以缓慢的变化率开始,并向中间加速。随着接近终点,它开始减速,即降低变化率。
- 预期插值器:此插值方法是先向后移动,然后向前“猛冲”,然后逐渐进行到结束。这使它具有类似于卡通的效果,在卡通中,字符在射击前要向后拉。例如,生成的值在1-> 3之间看起来像:1-> 0.5-> 2-> 2.5->3。请注意第一个生成的值如何“位于”起始值“之后”,以及它如何向前跳转到前面的值起始值。然后,它均匀地进行到端点。
- 反弹插值器:要了解此插值器,请考虑垂直站立在固体表面上的仪表刻度。起始值在顶部,结束值在底部,接触表面。现在考虑一下,一个落在仪表刻度旁边的球。击中表面的球会上下反弹几次,直到最终落在表面上。使用反弹插值器时,生成的值类似于球在仪表刻度旁边经过的值列表。例如,在1-> 5之间生成的值可以是1-> 2-> 3-> 4-> 5-> 4.2-> 5-> 4.5->5。注意生成的值如何反弹。
- 过冲插补器:此插补器从头到尾均匀地生成值。但是,到达终点后,它会超调或超出最后一个值一小部分,然后返回到端点。例如,在1-> 5之间生成的值可能类似于:1-> 2-> 3-> 4-> 5-> 5.5-> 5。
- 预期超调插值器:此插值器是预期和超调插值器的组合。也就是说,它首先从起始值向后退,向前猛冲并均匀地移动到端点,使它过冲,然后返回到端点。
创建应用
为了更好地理解上述类并查看它们的运行情况,强烈建议您跟随一个实际项目并在构建它时运行该应用程序。
- 启用和设置视图绑定(可选)
视图绑定是不久前推出的一项简洁的小功能,可以更轻松地在您的应用程序中使用视图。从本质上讲,它消除了findViewById调用,并为您提供了易于使用的视图的句柄。它们还使您的代码更整洁。这是一个非常简单的过程,您可以在官方文档中了解如何打开它并进行设置。但是,此步骤是可选的,如果您希望手动连接视图,也可以继续进行。最终结果只需要使您能够配置要配置的按钮即可。 - 创建布局
在您的activity_main.xml文件中,创建按钮列表,如下面的代码部分所示。布局基本上由不同按钮的重复代码组成,因此,如果您了解一个按钮的功能,则也可以将其应用于其他按钮。
步骤1:使用activity_main.xml文件
转到activity_main.xml文件,并参考以下代码。以下是activity_main.xml文件的代码。
XML
Java
// 2-second animation duration
final private static int ANIMATION_DURATION = 2000;
private ObjectAnimator animator;
Java
// Linear
binding.linear.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.linear,"translationX", 200f);
animator.setInterpolator(new LinearInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
Java
import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.BounceInterpolator;
import android.view.animation.CycleInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import androidx.appcompat.app.AppCompatActivity;
import com.example.doobar.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
// 2-second animation duration
final private static int ANIMATION_DURATION = 2000;
private ActivityMainBinding binding;
private ObjectAnimator animator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
// setup animation buttons
// Linear
binding.linear.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.linear, "translationX", 200f);
animator.setInterpolator(new LinearInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Accelerate
binding.accelerate.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.accelerate, "translationX", 200f);
animator.setInterpolator(new AccelerateInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Decelerate
binding.decelerate.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.decelerate, "translationX", 200f);
animator.setInterpolator(new DecelerateInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Bounce
binding.bounce.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.bounce, "translationX", 200f);
animator.setInterpolator(new BounceInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Overshoot
binding.overshoot.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.overshoot, "translationX", 200f);
animator.setInterpolator(new OvershootInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Anticipate
binding.anticipate.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.anticipate, "translationX", 200f);
animator.setInterpolator(new AnticipateInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Cycle
binding.cycle.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.cycle, "translationX", 200f);
animator.setInterpolator(new CycleInterpolator(2));
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Accelerate Decelerate
binding.accelerateDecelerate.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.accelerateDecelerate, "translationX", 200f);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Anticipate Overshoot
binding.anticipateOvershoot.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.anticipateOvershoot, "translationX", 200f);
animator.setInterpolator(new AnticipateOvershootInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
}
}
步骤2:使用MainActivity。 Java文件
设置ObjectAnimator对象:在本示例中,我们将使用单个ObjectAnimator为不同的按钮设置动画。我们还将使用固定的2秒持续时间来播放动画,这使我们有足够的时间来观察动画行为。您可以使用以下两行代码进行设置。
Java
// 2-second animation duration
final private static int ANIMATION_DURATION = 2000;
private ObjectAnimator animator;
单击按钮上的设置动画:现在,我们已经进行了先决条件设置,我们终于可以配置按钮来触发它们各自的动画了。对于每个按钮,您可以将特定属性配置为动画,其持续时间和插值等等。如下面的代码片段所示,执行基本的三步配置:
Java
// Linear
binding.linear.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.linear,"translationX", 200f);
animator.setInterpolator(new LinearInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
以下是MainActivity的完整代码。 Java文件。在代码内部添加了注释,以更详细地了解代码。
Java
import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.BounceInterpolator;
import android.view.animation.CycleInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import androidx.appcompat.app.AppCompatActivity;
import com.example.doobar.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
// 2-second animation duration
final private static int ANIMATION_DURATION = 2000;
private ActivityMainBinding binding;
private ObjectAnimator animator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
// setup animation buttons
// Linear
binding.linear.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.linear, "translationX", 200f);
animator.setInterpolator(new LinearInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Accelerate
binding.accelerate.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.accelerate, "translationX", 200f);
animator.setInterpolator(new AccelerateInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Decelerate
binding.decelerate.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.decelerate, "translationX", 200f);
animator.setInterpolator(new DecelerateInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Bounce
binding.bounce.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.bounce, "translationX", 200f);
animator.setInterpolator(new BounceInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Overshoot
binding.overshoot.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.overshoot, "translationX", 200f);
animator.setInterpolator(new OvershootInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Anticipate
binding.anticipate.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.anticipate, "translationX", 200f);
animator.setInterpolator(new AnticipateInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Cycle
binding.cycle.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.cycle, "translationX", 200f);
animator.setInterpolator(new CycleInterpolator(2));
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Accelerate Decelerate
binding.accelerateDecelerate.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.accelerateDecelerate, "translationX", 200f);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
// Anticipate Overshoot
binding.anticipateOvershoot.setOnClickListener(clickedView -> {
animator = ObjectAnimator.ofFloat(binding.anticipateOvershoot, "translationX", 200f);
animator.setInterpolator(new AnticipateOvershootInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.start();
});
}
}
输出:运行应用程序
制作完按钮并将其设置为在按下时触发动画后,您就可以启动该应用程序并看到生动的动画。大功告成!这就是在动画中使用插值器为它们加香料而不使它们看起来单调的方式。
您可以在这里查看整个应用程序:https://github.com/krishnakeshan/android-interpolators。