Interpolator 是被用来修饰动画效果,定义动画的变化率,可以使存在的动画效果accelerated(加速),decelerated(减速),repeated(重复),bounced(弹跳)等。
Interpolator中文意思是插补器(百度翻译),而用在Android动画中,可以理解为是用于动画中的时间插值,其作用就是把0到1的浮点值变化映射到另一个浮点值变化。
插补器分为:
AccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢,在中间的时候加速
AccelerateInterpolator 在动画开始的地方速率改变比较慢,然后开始加速
AnticipateInterpolator 开始的时候向后然后向前甩
AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值
BounceInterpolator 动画结束的时候弹起
CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线
DecelerateInterpolator 在动画开始的地方快然后慢
LinearInterpolator 以常量速率改变
OvershootInterpolator 向前甩一定值后再回到原来位置
我们如果要实现一个动画效果,可以继承Animation,然后在applyTransformation(float interpolatedTime, Transformation t)这个方法内去实现具体效果,而这个方法的第一个参数interpolatedTime就是动画时间,Interpolator的作用就是改变这个时间。
我们可以从源码看出,当一个动画调用了setInterpolator(Interpolator i),设置了插补器后,它是在什么时候启作用的呢?查看Animation.java这个动画父类,getTransformation(long currentTime, Transformation outTransformation),
public boolean getTransformation(long currentTime, Transformation outTransformation) {
if (mStartTime == -1) {
mStartTime = currentTime;
}
final long startOffset = getStartOffset();
final long duration = mDuration;
float normalizedTime;
if (duration != 0) {
normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /
(float) duration;
} else {
// time is a step-change with a zero duration
normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
}
final boolean expired = normalizedTime >= 1.0f;
mMore = !expired;
if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
if (!mStarted) {
fireAnimationStart();
mStarted = true;
if (USE_CLOSEGUARD) {
guard.open("cancel or detach or getTransformation");
}
}
if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
if (mCycleFlip) {
normalizedTime = 1.0f - normalizedTime;
}
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
applyTransformation(interpolatedTime, outTransformation);
}
if (expired) {
if (mRepeatCount == mRepeated) {
if (!mEnded) {
mEnded = true;
guard.close();
fireAnimationEnd();
}
} else {
if (mRepeatCount > 0) {
mRepeated++;
}
if (mRepeatMode == REVERSE) {
mCycleFlip = !mCycleFlip;
}
mStartTime = -1;
mMore = true;
fireAnimationRepeat();
}
}
if (!mMore && mOneMoreTime) {
mOneMoreTime = false;
return true;
}
return mMore;
}
看37、38行那两句,mInterpolator变量就是我们前面调用
setInterpolator设置的插补器对象,然后将mInterpolator.getInterpolation()的返回值当作第一个参数去执行applyTransformation,所以我们可以看出Interpolator对动画变化效果起到辅助作用的。我们就用平移动画效果来讲Interpolator是怎么起辅助作用的。
看下TranslateAnimation的applyTransformation方法
protected void applyTransformation(float interpolatedTime, Transformation t) {
float dx = mFromXDelta;
float dy = mFromYDelta;
if (mFromXDelta != mToXDelta) {
dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
}
if (mFromYDelta != mToYDelta) {
dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
}
t.getMatrix().setTranslate(dx, dy);
}
平移的(dx,dy)是根据参数interpolatedTime变化的,比如,我们给平移动画设置加速插补器AccelerateInterpolator
,这个插补器的变化是怎样的呢?
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
默认的话即mFactor=1.0f,它是一个y=x^2 (0<x<1)的变化曲线,如果你希望这个加速度更快点的话,可以使用这个构造函数
public AccelerateInterpolator(float factor) {
mFactor = factor;
mDoubleFactor = 2 * mFactor;
}
这时它的变化曲线为y=x^(2*mFactor)(0<x<1),我们都知道这个函数是一个幂函数,是一个递增函数,变化速度越来越快,所以当平移动画设置了该加速插补器,它平移的速度是递增的。其他插补器这里就不多说了,请戳 其他Interpolator说明
接下来我们看下效果
public class InterpolatorAnimationActivity extends Activity implements
AdapterView.OnItemSelectedListener {
private static final String[] INTERPOLATORS = { "Accelerate", "Decelerate",
"Accelerate/Decelerate", "Anticipate", "Overshoot",
"Anticipate/Overshoot", "Bounce", "LinearInterpolator",
"CycleInterpolator" };
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_interpolator_animation);
Spinner s = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, INTERPOLATORS);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s.setAdapter(adapter);
s.setOnItemSelectedListener(this);
}
public void onItemSelected(AdapterView<?> parent, View v, int position,
long id) {
final View target = findViewById(R.id.target);
final View targetParent = (View) target.getParent();
Animation a = new TranslateAnimation(// 平移动画
0.0f, targetParent.getWidth() - target.getWidth()
- targetParent.getPaddingLeft()
- targetParent.getPaddingRight(), 0.0f, 0.0f);
a.setDuration(1000);
a.setStartOffset(300);
a.setRepeatMode(Animation.RESTART);
a.setRepeatCount(Animation.INFINITE);
switch (position) {
case 0:
// 加速插值器 速度变化公式y=x^2(默认)
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.accelerate_interpolator));
break;
case 1:
// 减速插值器
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.decelerate_interpolator));
break;
case 2:
// 加速减速插值器
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.accelerate_decelerate_interpolator));
break;
case 3:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.anticipate_interpolator));
break;
case 4:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.overshoot_interpolator));
break;
case 5:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.anticipate_overshoot_interpolator));
break;
case 6:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.bounce_interpolator));
break;
case 7:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.linear_interpolator));
break;
case 8:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.cycle_interpolator));
break;
}
target.startAnimation(a);
}
public void onNothingSelected(AdapterView<?> parent) {
}
}
activity_interpolator_animation.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="10dip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false">
<TextView
android:id="@+id/target"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="26sp"
android:text="Interpolators"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dip"
android:layout_marginBottom="5dip"
android:text="Select an animation" />
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>