在 Android开发中,为了保持良好的交互体验,我们经常会用到动画来提升用户体验,而动画中属性动画用的最多。
虽然动画可以让界面看起来不是那么粗糙,但是很多时候仅仅只是匀速运动的动画可能不足以描述一些我们想呈现给用户的界面,比如模拟一个下落的小球,我们知道下落的小球并不是以匀速运动的,而是加速下落的,如果要实现这样一个效果,我们可能就需要用到 Time Interpolator 。
其实 Android
已经给我们提供了若干类型的 interpolator
供我们使用,一般情况下这些已经足够我们使用了,所以也就不需要我们自己创造了,下面我们就具体了解一下各个类型的 interpolator
的使用方法和适用场景。
AccelerateDecelerateInterpolator
缓慢启动,中间过程移动非常快,缓慢结束,适用于在屏幕上启动和结束的动画。AccelerateInterpolator
缓慢启动,在移动过程中慢慢加快,适用于在屏幕上启动,屏幕外结束的动画。AnticipateInterpolator
类似于AccelerateInterpolator
,但是有一个导致它以负值启动的弹力,一次一个物体向下移动的动画会先向上移动,然后再向下移动,可以理解为把一个物体放在一个弹弓上向后拉然后弹射出去。AnticipateOvershootInterpolator
前半部分与AnticipateInterpolator
相同,到达终点后会继续以这个速度继续向原来的方向运动一段距离之后再回到终点。BounceInterpolator
类似于一个有弹性的小球掉到地上,然后又弹回来,再落下去,但是每次弹起来的高度会越来越低,直到最终静止在地面上。CycleInterpolator
运动曲线类似于sin
函数,起始位置相当于sin
零点,终点相当于sin
的顶点。比如有一个处于中心的一个小球,你的目标是把它移到下方的一个位置,这个位置暂称之为终点,那这个小球的运动轨迹会是 : 先向下移动到终点,然后再向上移动到初始位置,然后在向上移动 初始位置到终点 同样的距离,然后再返回到初始位置。这是一个周期,至于动画会执行几个周期,这取决于你在构造函数中传入的浮点参数,这个参数就是周期。DecelerateInterpolator
以最大速度启动,结束时放慢速度,适用于在屏幕之外启动,在屏幕内结束的动画。FastOutLinearInInterpolator
在support
库中,这个插值器使用一个查找表来描述位移。简单的说,它的启动过程像AccelerateInterpolator
,结束过程像LinearInterpolator
。FastOutSlowInInterpolator
在support
库中,这个插值器也是使用一个查找表来描述位移。它的启动过程像AccelerateInterpolator
,结束过程像DecelerateInterpolator
。LinearInterpolator
以一个恒定的速度变化的动画。LinearOutSlowInInterpolator
在support
库中,这个插值器也是使用一个查找表来描述位移。它的启动过程像LinearInterpolator
,结束过程像DecelerateInterpolator
。OvershootInterpolator
类似于AccelerateInterpolator
,但是有一个是它不能立即停到终点位置的力,使它超过终点位置,然后在弹回终点,就想撞到了弹弓上。PathInterpolator
这个是在Android 5.0(API level 21)
中加入的,这个插值动画基于你穿给它的一个路径。X
坐标表示时间,Y
坐标代表返回的浮点值。如果你任意给定的X
值只对应一个Y
值,并且没有间断(即一段给定的0~1
之间的X
值对应一段连续的Y
值),那么所有种类的路径都可以被支持。
我们来看一下使用各个 interpolator
的运行效果。
下面附上源码:
testActivity.class
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.support.v4.view.animation.FastOutLinearInInterpolator;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.support.v4.view.animation.LinearOutSlowInInterpolator;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
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 android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
public class testActivity extends AppCompatActivity {
ImageView testImage;
ObjectAnimator mObjectAnimator;
TimeInterpolator mTimeInterpolator;
String currentInterpolator = "AccelerateDecelerateInterpolator";
int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏标题栏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);//隐藏状态栏
setContentView(R.layout.activity_test);
testImage = findViewById(R.id.image_test);
mObjectAnimator = ObjectAnimator.ofFloat(testImage,"translationY",0,600);
mObjectAnimator.setDuration(2000);
mTimeInterpolator = new AccelerateDecelerateInterpolator();
mObjectAnimator.setInterpolator(mTimeInterpolator);
Button startButton = findViewById(R.id.testButton);
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mObjectAnimator.setInterpolator(mTimeInterpolator);
mObjectAnimator.start();
}
});
final TextView stringAcc = findViewById(R.id.stringAcc);
stringAcc.setText("AccelerateDecelerateInterpolator");
Button next =findViewById(R.id.nextButton);
next.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
count ++;
if(count>11){
count = 0;
}
switch(count){
case 0:mTimeInterpolator = new AccelerateDecelerateInterpolator();
currentInterpolator = "AccelerateDecelerateInterpolator";break;
case 1:mTimeInterpolator = new AccelerateInterpolator();
currentInterpolator = "AccelerateInterpolator";break;
case 2:mTimeInterpolator = new AnticipateInterpolator();
currentInterpolator = "AnticipateInterpolator";break;
case 3:mTimeInterpolator = new AnticipateOvershootInterpolator();
currentInterpolator = "AnticipateOvershootInterpolator";break;
case 4:mTimeInterpolator = new BounceInterpolator();
currentInterpolator = "BounceInterpolator";break;
case 5:mTimeInterpolator = new CycleInterpolator(1.0f);
mObjectAnimator = ObjectAnimator.ofFloat(testImage,"translationX",0,250);
mObjectAnimator.setDuration(2000);
currentInterpolator = "CycleInterpolator";break;
case 6:mTimeInterpolator = new DecelerateInterpolator();
mObjectAnimator = ObjectAnimator.ofFloat(testImage,"translationY",0,600);
mObjectAnimator.setDuration(2000);
currentInterpolator = "DecelerateInterpolator";break;
case 7:mTimeInterpolator = new FastOutLinearInInterpolator();
currentInterpolator = "FastOutLinearInInterpolator";break;
case 8:mTimeInterpolator = new FastOutSlowInInterpolator();
currentInterpolator = "FastOutSlowInInterpolator";break;
case 9:mTimeInterpolator = new LinearInterpolator();
currentInterpolator = "LinearInterpolator";break;
case 10:mTimeInterpolator = new LinearOutSlowInInterpolator();
currentInterpolator = "LinearOutSlowInInterpolator";break;
case 11:mTimeInterpolator = new OvershootInterpolator();
currentInterpolator = "OvershootInterpolator";break;
}
stringAcc.setText(currentInterpolator);
}
});
}
}
activity_test.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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"
tools:context="com.tobetheonlyone.testActivity"
android:background="#ede7e7">
<ImageView
android:id="@+id/image_test"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentTop="true"
android:layout_marginTop="30dp"
android:layout_centerHorizontal="true"
android:background="@drawable/text_round"/>
<Button
android:id="@+id/testButton"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp"
android:background="@drawable/btn_green"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:text="开始"/>
<Button
android:id="@+id/nextButton"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_above="@+id/testButton"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:background="@drawable/btn_green"
android:text="下一个"/>
<TextView
android:id="@+id/stringAcc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/nextButton"
android:layout_marginBottom="10dp"
android:layout_centerHorizontal="true"
android:textSize="25sp"/>
</RelativeLayout>
btn_green.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
<shape >
<solid
android:color="#07e18c" />
<stroke
android:width="1.0dp"
android:color="#07e18c" />
<corners
android:radius="3dp" />
</shape>
</item>
<item>
<shape >
<stroke
android:width="2.0dp"
android:color="#06f799" />
<corners
android:radius="3dp" />
</shape>
</item>
text_round.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<size android:width="100dp" android:height="100dp"/>
<solid android:color="#29694d"/>
</shape>
</item>
</selector>
PS:推荐一个优惠券网站:优惠券领取-券券猫