Interpolator 被用来修饰动画效果,定义动画的变化率。在Android源码中对应的接口类为TimeInterpolator,通过输入均匀变化的0~1之间的值,可以得到匀速、正加速、负加速、无规则变加速等0~1之间的变化曲线

曲线举例:

如下图所示,为Android源码中OvershootInterpolator插值器变化率曲线。

输入均匀变化0~1.0f之间浮点值,输出先加速超过临界值1.0f 再慢慢又回落到1.0f 连续变化的浮点值。

效果举例:

使用OvershootInterpolator动画插值器后,动画的运行效果如下所示:

上图中,旋转放大效果中,旋转动画就是使用了OvershootInterpolator动画插值器。

可以看到3D勋章 360度旋转时,旋转角度先超过了360度,然后慢慢又回到了360度位置,从而呈现一个回弹的视觉效果

注:

了解 3D勋章具体实现,参考文章《3D勋章实现方案》:

https://xiaxl.blog.csdn.net/article/details/77048507

  • Android 源码中的动画插值器
  • Easing 经典动画插值器

一、Android中的插值器

Android源码中使用 TimeInterpolator 接口修饰动画效果,定义动画的变化率。

代码位于android.animation包下,只包含一个抽象方法为getInterpolation(float input)

// 位于android.animation包下
package android.animation;
// Android源码中的 动画插值器
public interface TimeInterpolator {
// 差值计算(输入为0~1.0f之间的浮点值,输出为连续的变化率曲线)
float getInterpolation(float input);
}

TimeInterpolator接口类中,只有一个方法float getInterpolation(float input),根据输入的浮点值input(0~1.0f之间),输出为连续的变化率曲线。

Android中动画插值器的使用方式如下:

// view 位移动画
AnimatorSet localAnimatorSet = new AnimatorSet();
float[] arrayOfFloat = new float[2];
arrayOfFloat[0] = y0;
arrayOfFloat[1] = y1;
// 位移动画使用了 DecelerateInterpolator() 动画插值器
// 动画效果:先位移超过临界值,再回到临界值
ObjectAnimator localObjectAnimator = ObjectAnimator.ofFloat(view,
"translationY", arrayOfFloat);
localObjectAnimator.setDuration(240L);
localObjectAnimator.setInterpolator(new DecelerateInterpolator());
localAnimatorSet.play(localObjectAnimator);
localAnimatorSet.start();

TimeInterpolator为接口类,其有如下接口实现类。

1.1 AccelerateDecelerateInterpolator

AccelerateDecelerateInterpolator 该插值器运动曲线 两边慢 中间快,其运动曲线如下图所示:

/**
* An interpolator where the rate of change starts and ends slowly but
* accelerates through the middle.
* 两边慢 中间快
*/
public class AccelerateDecelerateInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
public AccelerateDecelerateInterpolator() {
} public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
}

1.2 AccelerateInterpolator

AccelerateInterpolator 该插值器运动曲线 先慢 后快,其运动曲线如下图所示(factor值为1):

/**
* An interpolator where the rate of change starts out slowly and
* and then accelerates.
* 先慢 后快
*/
public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
private final float mFactor;
private final double mDoubleFactor; public AccelerateInterpolator() {
mFactor = 1.0f;
mDoubleFactor = 2.0;
} /**
* Constructor
*
* @param factor Degree to which the animation should be eased. Seting
* factor to 1.0f produces a y=x^2 parabola. Increasing factor above
* 1.0f exaggerates the ease-in effect (i.e., it starts even
* slower and ends evens faster)
*/
public AccelerateInterpolator(float factor) {
mFactor = factor;
mDoubleFactor = 2 * mFactor;
} public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
}

1.3 AnticipateInterpolator

AnticipateInterpolator 该插值器运动曲线 先向后超过临界值,再快速向前,像一个回荡的秋千,因此被称为回荡秋千插值器曲线图如下:

/**
* An interpolator where the change starts backward then flings forward.
* 先向后 再向前
*/
public class AnticipateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
private final float mTension; public AnticipateInterpolator() {
mTension = 2.0f;
} /**
* @param tension Amount of anticipation. When tension equals 0.0f, there is
* no anticipation and the interpolator becomes a simple
* acceleration interpolator.
*/
public AnticipateInterpolator(float tension) {
mTension = tension;
} public float getInterpolation(float t) {
// a(t) = t * t * ((tension + 1) * t - tension)
return t * t * ((mTension + 1) * t - mTension);
}
}

1.4 AnticipateOvershootInterpolator

AnticipateOvershootInterpolator 该插值器运动曲线 先向后运动 超过临界值,再快速向前运动到达临界值,其运动曲线如下图所示:

/**
* An interpolator where the change starts backward then flings forward and overshoots
* the target value and finally goes back to the final value.
* 先向后运动 超过临界值,再快速向前运动超过临界值,最后慢慢回到临界值
*/
public class AnticipateOvershootInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
private final float mTension; public AnticipateOvershootInterpolator() {
mTension = 2.0f * 1.5f;
} /**
* @param tension Amount of anticipation/overshoot. When tension equals 0.0f,
* there is no anticipation/overshoot and the interpolator becomes
* a simple acceleration/deceleration interpolator.
*/
public AnticipateOvershootInterpolator(float tension) {
mTension = tension * 1.5f;
} /**
* @param tension Amount of anticipation/overshoot. When tension equals 0.0f,
* there is no anticipation/overshoot and the interpolator becomes
* a simple acceleration/deceleration interpolator.
* @param extraTension Amount by which to multiply the tension. For instance,
* to get the same overshoot as an OvershootInterpolator with
* a tension of 2.0f, you would use an extraTension of 1.5f.
*/
public AnticipateOvershootInterpolator(float tension, float extraTension) {
mTension = tension * extraTension;
} private static float a(float t, float s) {
return t * t * ((s + 1) * t - s);
} private static float o(float t, float s) {
return t * t * ((s + 1) * t + s);
} public float getInterpolation(float t) {
// a(t, s) = t * t * ((s + 1) * t - s)
// o(t, s) = t * t * ((s + 1) * t + s)
// f(t) = 0.5 * a(t * 2, tension * extraTension), when t < 0.5
// f(t) = 0.5 * (o(t * 2 - 2, tension * extraTension) + 2), when t <= 1.0
if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
}
}

1.5 BounceInterpolator

BounceInterpolator 该插值器运动曲线 快速运动到临界值后,进行几次回跳,类似一个从高空坠落篮球的运动曲线,其运动曲线如下图所示:

/**
* An interpolator where the change bounces at the end.
* 快速运动到临界值后,进行几次回跳,类似一个从高空坠落篮球的运动曲线。
*/
public class BounceInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public BounceInterpolator() {
} private static float bounce(float t) {
return t * t * 8.0f;
} public float getInterpolation(float t) {
// _b(t) = t * t * 8
// bs(t) = _b(t) for t < 0.3535
// bs(t) = _b(t - 0.54719) + 0.7 for t < 0.7408
// bs(t) = _b(t - 0.8526) + 0.9 for t < 0.9644
// bs(t) = _b(t - 1.0435) + 0.95 for t <= 1.0
// b(t) = bs(t * 1.1226)
t *= 1.1226f;
if (t < 0.3535f) return bounce(t);
else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f;
else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
else return bounce(t - 1.0435f) + 0.95f;
}
}

1.6 CycleInterpolator

CycleInterpolator 该插值器运动曲线 正弦变化曲线,其运动曲线如下图所示:

/**
* Repeats the animation for a specified number of cycles. The
* rate of change follows a sinusoidal pattern.
* sin正弦变化曲线
*/
@HasNativeInterpolator
public class CycleInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
private float mCycles; public CycleInterpolator(float cycles) {
mCycles = cycles;
} public float getInterpolation(float input) {
return (float)(Math.sin(2 * mCycles * Math.PI * input));
}
}

1.7 DecelerateInterpolator

DecelerateInterpolator 该插值器运动曲线 减速插值器变化曲线,其算法为AccelerateInterpolator的完全倒置,同样有DecelerateInterpolator(float factor)构造函数来指定mFactor运动曲线如下图所示(factor值为1):

/**
* An interpolator where the rate of change starts out quickly and
* and then decelerates.
* 减速插值器变化曲线,其算法为AccelerateInterpolator的完全倒置。
*/
public class DecelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
private float mFactor = 1.0f; public DecelerateInterpolator() {
} /**
* Constructor
*
* @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces
* an upside-down y=x^2 parabola. Increasing factor above 1.0f exaggerates the
* ease-out effect (i.e., it starts even faster and ends evens slower).
*/
public DecelerateInterpolator(float factor) {
mFactor = factor;
} public float getInterpolation(float input) {
float result;
if (mFactor == 1.0f) {
result = (float)(1.0f - (1.0f - input) * (1.0f - input));
} else {
result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));
}
return result;
}
}

1.8 LinearInterpolator

LinearInterpolator 该插值器运动曲线 为0~1之间匀速变化的一条直线,其运动曲线如下图所示:

/**
* An interpolator where the rate of change starts out quickly and
* and then decelerates.
* 为0~1之间匀速变化的一条直线。
*/
/**
* An interpolator where the rate of change is constant
*/
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { public LinearInterpolator() {
} public float getInterpolation(float input) {
return input;
}
}

1.9 OvershootInterpolator

OvershootInterpolator 该插值器运动曲线 先加速超过临界值1.0f 再慢慢又回落到1.0f,有一个回弹的效果

可使用OvershootInterpolator(float tension)构造函数设置mTension弹力值,mTension值越大,超出目标值的时间点越靠前,超出目标值的回弹距离越大,回弹越明显。

其运动曲线如下图所示:

/**
* An interpolator where the change flings forward and overshoots the last value
* then comes back.
* 先超过临界值 再慢慢回到临界值
*/
public class OvershootInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
private final float mTension; public OvershootInterpolator() {
mTension = 2.0f;
} /**
* @param tension Amount of overshoot. When tension equals 0.0f, there is
* no overshoot and the interpolator becomes a simple
* deceleration interpolator.
*/
public OvershootInterpolator(float tension) {
mTension = tension;
} public float getInterpolation(float t) {
// _o(t) = t * t * ((tension + 1) * t + tension)
// o(t) = _o(t - 1) + 1
t -= 1.0f;
return t * t * ((mTension + 1) * t + mTension) + 1.0f;
}
}

1.10 PathInterpolator

PathInterpolator 可以称之为万能插值器,可以通过PathInterpolator构造一个Path路径 或 通过传入点来构造一个贝塞尔曲线(通过这个贝塞尔曲线,我们可以构造任意的变化曲线)。

//创建一个任意Path的插值器
PathInterpolator(Path path)
//创建一个二阶贝塞尔曲线的插值器
PathInterpolator(float controlX, float controlY)
//创建一个三阶贝塞尔曲线的插值器
PathInterpolator(float controlX1, float controlY1, float controlX2, float controlY2)

贝塞尔曲线的构建,可以使用如下辅助工具 cubic-bezier

https://cubic-bezier.com/


/**
* An interpolator that can traverse a Path that extends from <code>Point</code>
* <code>(0, 0)</code> to <code>(1, 1)</code>. The x coordinate along the <code>Path</code>
* is the input value and the output is the y coordinate of the line at that point.
* This means that the Path must conform to a function <code>y = f(x)</code>.
*
* <p>The <code>Path</code> must not have gaps in the x direction and must not
* loop back on itself such that there can be two points sharing the same x coordinate.
* It is alright to have a disjoint line in the vertical direction:</p>
* <p><blockquote><pre>
* Path path = new Path();
* path.lineTo(0.25f, 0.25f);
* path.moveTo(0.25f, 0.5f);
* path.lineTo(1f, 1f);
* </pre></blockquote></p>
* 构造一个普通Path路径或者贝塞尔曲线的插值器
*/
public class PathInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { // This governs how accurate the approximation of the Path is.
private static final float PRECISION = 0.002f; private float[] mX; // x coordinates in the line private float[] mY; // y coordinates in the line /**
* Create an interpolator for an arbitrary <code>Path</code>. The <code>Path</code>
* must begin at <code>(0, 0)</code> and end at <code>(1, 1)</code>.
*
* @param path The <code>Path</code> to use to make the line representing the interpolator.
*/
public PathInterpolator(Path path) {
initPath(path);
} public PathInterpolator(float controlX, float controlY) {
initQuad(controlX, controlY);
} /**
* Create an interpolator for a cubic Bezier curve. The end points
* <code>(0, 0)</code> and <code>(1, 1)</code> are assumed.
*
* @param controlX1 The x coordinate of the first control point of the cubic Bezier.
* @param controlY1 The y coordinate of the first control point of the cubic Bezier.
* @param controlX2 The x coordinate of the second control point of the cubic Bezier.
* @param controlY2 The y coordinate of the second control point of the cubic Bezier.
*/
public PathInterpolator(float controlX1, float controlY1, float controlX2, float controlY2) {
initCubic(controlX1, controlY1, controlX2, controlY2);
} private void initQuad(float controlX, float controlY) {
Path path = new Path();
path.moveTo(0, 0);
path.quadTo(controlX, controlY, 1f, 1f);
initPath(path);
} private void initCubic(float x1, float y1, float x2, float y2) {
Path path = new Path();
path.moveTo(0, 0);
path.cubicTo(x1, y1, x2, y2, 1f, 1f);
initPath(path);
} private void initPath(Path path) {
float[] pointComponents = path.approximate(PRECISION); int numPoints = pointComponents.length / 3;
if (pointComponents[1] != 0 || pointComponents[2] != 0
|| pointComponents[pointComponents.length - 2] != 1
|| pointComponents[pointComponents.length - 1] != 1) {
throw new IllegalArgumentException("The Path must start at (0,0) and end at (1,1)");
} mX = new float[numPoints];
mY = new float[numPoints];
float prevX = 0;
float prevFraction = 0;
int componentIndex = 0;
for (int i = 0; i < numPoints; i++) {
float fraction = pointComponents[componentIndex++];
float x = pointComponents[componentIndex++];
float y = pointComponents[componentIndex++];
if (fraction == prevFraction && x != prevX) {
throw new IllegalArgumentException(
"The Path cannot have discontinuity in the X axis.");
}
if (x < prevX) {
throw new IllegalArgumentException("The Path cannot loop back on itself.");
}
mX[i] = x;
mY[i] = y;
prevX = x;
prevFraction = fraction;
}
} /**
* Using the line in the Path in this interpolator that can be described as
* <code>y = f(x)</code>, finds the y coordinate of the line given <code>t</code>
* as the x coordinate. Values less than 0 will always return 0 and values greater
* than 1 will always return 1.
*
* @param t Treated as the x coordinate along the line.
* @return The y coordinate of the Path along the line where x = <code>t</code>.
* @see Interpolator#getInterpolation(float)
*/
@Override
public float getInterpolation(float t) {
if (t <= 0) {
return 0;
} else if (t >= 1) {
return 1;
}
// Do a binary search for the correct x to interpolate between.
int startIndex = 0;
int endIndex = mX.length - 1; while (endIndex - startIndex > 1) {
int midIndex = (startIndex + endIndex) / 2;
if (t < mX[midIndex]) {
endIndex = midIndex;
} else {
startIndex = midIndex;
}
} float xRange = mX[endIndex] - mX[startIndex];
if (xRange == 0) {
return mY[startIndex];
} float tInRange = t - mX[startIndex];
float fraction = tInRange / xRange; float startY = mY[startIndex];
float endY = mY[endIndex];
return startY + (fraction * (endY - startY));
}
}

1.11 OvershootInterpolator

OvershootInterpolator 该插值器运动曲线 先加速超过临界值1.0f 再慢慢又回落到1.0f,有一个回弹的效果

可使用OvershootInterpolator(float tension)构造函数设置mTension弹力值,mTension值越大,超出目标值的时间点越靠前,超出目标值的回弹距离越大,回弹越明显。

其运动曲线如下图所示:

/**
* An interpolator where the change flings forward and overshoots the last value
* then comes back.
* 先超过临界值 再慢慢回到临界值
*/
public class OvershootInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
private final float mTension; public OvershootInterpolator() {
mTension = 2.0f;
} /**
* @param tension Amount of overshoot. When tension equals 0.0f, there is
* no overshoot and the interpolator becomes a simple
* deceleration interpolator.
*/
public OvershootInterpolator(float tension) {
mTension = tension;
} public float getInterpolation(float t) {
// _o(t) = t * t * ((tension + 1) * t + tension)
// o(t) = _o(t - 1) + 1
t -= 1.0f;
return t * t * ((mTension + 1) * t + mTension) + 1.0f;
}
}

注:

使用PathInterpolator插值器会消耗更多的内存,不同于其他简单插值器,一般的插值器都是在算法上来生成插值,而PathInterpolator是在初始化时依赖Path算法生成一系列插值点存储,源码显示是以0.02为step在0到1范围内取点,生成500个x样本和500个y样本共计1000个float数据,相比其他插值器消耗了相当1000倍的内存,虽然对目前手机性能来说微不足道,但在动画这种要求高性能的操作时建议谨慎使用,不要频繁初始化,尽量复用同参数的插值器,以提高性能。

二、Easing 插值器

Easing算法是业界著名的一组插值器算法,涵盖了各种速率的曲线算法。

其涵盖的曲线算法如下图所示:

注:

easings 官方网址:

https://easings.net/

easeInOutBounce

举例一个动画插值器 easeInOutBounce。Easing官方对于每一个动画插值器,均给出了完整的算法实现动画运动曲线,开发者可以根据自己的需要自行选择对应的插值器算法,构造自己的动画插值器。

function easeInOutBounce(x: number): number {
return x < 0.5
? (1 - easeOutBounce(1 - 2 * x)) / 2
: (1 + easeOutBounce(2 * x - 1)) / 2;
}

三、调试插值器

调试动画插值器,可以使用如下小工具:

wolframalpha 调试动画插值器:

https://www.wolframalpha.com/input/?i=x%5E%282*3%29%280%3Cx%3C%3D1%29

参考

wolframalpha调试工具:

https://www.wolframalpha.com/input/?i=x%5E%282*3%29%280%3Cx%3C%3D1%29

cubic-bezier辅助工具:

https://cubic-bezier.com/

easings 插值器:

https://easings.net/

3D勋章实现方案:

https://xiaxl.blog.csdn.net/article/details/77048507

= THE END =

详解 Interpolator动画插值器的更多相关文章

  1. [转]ANDROID L——Material Design详解(动画篇)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 转自:http://blog.csdn.net/a396901990/article/de ...

  2. ios学习--详解IPhone动画效果类型及实现方法

    详解IPhone动画效果类型及实现方法是本文要介绍的内容,主要介绍了iphone中动画的实现方法,不多说,我们一起来看内容. 实现iphone漂亮的动画效果主要有两种方法,一种是UIView层面的,一 ...

  3. css 12-CSS3属性详解:动画详解

    12-CSS3属性详解:动画详解 #前言 本文主要内容: 过渡:transition 2D 转换 transform 3D 转换 transform 动画:animation #过渡:transiti ...

  4. TranslateAnimation详解 Android动画。

    TranslateAnimation详解 Android JDK为我们提供了4种动画效果,分别是: AlphaAnimation,RotateAnimation, ScaleAnimation, Tr ...

  5. 属性动画详解 Interpolator TypeEvaluator

    概述 产生原因         3.0以前,android支持两种动画模式,tween animation,frame animation,在android3.0中又引入了一个新的动画系统:prope ...

  6. 【Android】详解Android动画之Interpolator插入器

    Interpolator英文意思是: 篡改者; 分类机; 校对机 SDK对Interpolator的描述是:An interpolator defines the rate of change of ...

  7. 详解Android动画之Tween Animation

    前面讲了动画中的Frame动画,今天就来详细讲解一下Tween动画的使用. 同样,在开始实例演示之前,先引用官方文档中的一段话: Tween动画是操作某个控件让其展现出旋转.渐变.移动.缩放的这么一种 ...

  8. 【Android】详解Android动画

    目录结构: contents structure [+] 补间动画 使用java代码实现Alpha.Rotate.Scale.Translate动画 通过xml文件实现Alpha.Rotate.Sca ...

  9. [转]Android 5.0——Material Design详解(动画篇)

    Material Design:Google推出的一个全新的设计语言,它的特点就是拟物扁平化. Material Design包含了很多内容,今天跟大家分享一下Material新增的动画: 在Andr ...

随机推荐

  1. Python urllib翻译笔记一

    22.5.urllib- URL处理模块urllib 是一个收集几个模块以处理URL的包: urllib.request 用于打开和阅读URL urllib.error 包含由urllib.reque ...

  2. GeoServer Rest服务启动匿名认证的配置方法

    GeoServer Rest服务数据默认需要进行用户名.密码的认证,如不需进行该认证,则启动匿名认证即可,配置方式如下(针对war包发布的GeoServer应用): 在GeoServer war包的解 ...

  3. 本地图片转base64编码

    通常获取图片的base64编码都是通过input的上传file属性获取转化,但是有时候需要的是本地图片不经过上传操作,直接拿本地图片转成base64编码就不行了,input上传操作需要人为操作一下,没 ...

  4. 大数据学习(11)—— Hive元数据服务模式搭建

    这一篇介绍Hive的安装及操作.版本是Hive3.1.2. 调整部署节点 在Hadoop篇里,我用了5台虚拟机来搭建集群,但是我的电脑只有8G内存,虚拟机启动之后卡到没法操作,把自己坑惨了. Hive ...

  5. Python: 解析crontab正则,增加+操作

    以下是使用Python解析crontab时间格式的一个类, 同时minute和hour支持了 + 的操作. 记录一下备忘. 其中的line参数是字符串分拆后的格式, 包含了 "week&qu ...

  6. GooseFS助力大数据业务数倍提升计算能力

    前言 GooseFS是由腾讯云推出的一款分布式缓存方案,主要针对包括需要缓存加速的数据湖业务场景,提供基于对象存储COS服务的近计算端数据加速层. GooseFS 基于开源大数据缓存方案 Alluxi ...

  7. 为了彻底搞懂 hashCode,我钻了一下 JDK 的源码

    今天我们来谈谈 Java 中的 hashCode() 方法--通过源码的角度.众所周知,Java 是一门面向对象的编程语言,所有的类都会默认继承自 Object 类,而 Object 的中文意思就是& ...

  8. 苹果手机点击输入框input 页面放大 超出屏幕问题

     <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale ...

  9. PWN——ret2dl_resolve

    PWN--ret2dl_resolve ret2dl_resolve是栈溢出中,底层且高级的一种利用手段,这里特此做一篇笔记学习一下. 个人认为,要掌握这种方法,自己去写demo来多次调试分析是不二法 ...

  10. XCTF-open-source

    下载附件拿到源码. #include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { if ( ...