A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 大山哥哥 于 2017-7-25 16:50 编辑

        在Android中学习动画的时候有一个东西大家应该都不陌生,就是Interpolator这个类,翻译过来是插值器的意思。但是大多数同学还是对它一头雾水,不知道是什么,也不知道用来干什么,所以在设置动画的时候就从来不设置这个值。但是在实际开发应用的过程中,这个插值器却是非常有用的,我们经常会用它来实现一些酷炫的动画效果。那我们今天就从源码开始分析,看一看Interpolator究竟怎么用。
        Interpolator 这个时间插值类,其主要使用在动画中,其作用主要是控制目标变量的变化值进行对应的变化。通俗一点来解释,举个生活中的例子,一辆车要行驶10公里到达目的地,刚开始速度为0,要一点点加速到某个值,再匀速行驶一段时间,最后再慢慢减速,最终到达目的地,速度为0.那我们如果用动画来描述的话,怎么来表示加速、减速的过程呢,例如位移动画,就是说了下时间,位移多长,根本没有速度的设置啊,所以Interpolator就登场了,用它我们就可以控制动画运行的进度。
        首先看一下这个类的源码。
[AppleScript] 纯文本查看 复制代码
/**
 * An interpolator defines the rate of change of an animation. This allows
 * the basic animation effects (alpha, scale, translate, rotate) to be 
 * accelerated, decelerated, repeated, etc.
 */
public interface Interpolator extends TimeInterpolator {
    // A new interface, TimeInterpolator, was introduced for the new android.animation
    // package. This older Interpolator interface extends TimeInterpolator so that users of
    // the new Animator-based animations can use either the old Interpolator implementations or
    // new classes that implement TimeInterpolator directly.
}

        What?是个接口,没有代码,还没有方法声明,那岂不是个废物,仔细一看它有个父接口,我们看一看父接口的源码。
[AppleScript] 纯文本查看 复制代码
/**
 * A time interpolator defines the rate of change of an animation. This allows animations
 * to have non-linear motion, such as acceleration and deceleration.
 */
public interface TimeInterpolator {

    /**
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float getInterpolation(float input);
}
        总算是有个方法了,在所继承的接口中有一个方法 float getInterpolation(float input)。在这个方法中,传入的值是一个0.0~1.0的值,返回值可以小于0.0也可以大于1.0。你可以这么理解:如果在Animation中时间是正常走的,你设置了200ms,现在走到了100ms了,那么按照线性来说现在应该是走了一半的路程也就是0.5。现在就把这0.5传递给Interpolator 让 Interpolator 告诉我走到一半时间的时候此时在哪里,这也就是 Interpolator 的原理。那如果我传的值是0.3,那说明进度是比线性的少的,但后面我们可以加速把这个进度补回来。所以可以灵活的控制这个方法的返回值达到我们的目的。而input的值是系统回调的时候传入的,也就是时间的进度,例如传过来0.5代表时间过去一半了,这时候你设置的方法的返回值就是运行效果的总进度。旋转动画就是角度,位移就是总距离等。
       那让我们自己写不会写啊,上学的时候数学没好好听啊,怎么办?AndroidSDK里有几个已经实现好的,我们来捋一捋。
              1.AccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢,在中间的时候加速
              2.AccelerateInterpolator  在动画开始的地方速率改变比较慢,然后开始加速   
              3.AnticipateInterpolator 开始的时候向后然后向前甩
              4.AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值
              5.BounceInterpolator   动画结束的时候弹起
              6.CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线
              7.DecelerateInterpolator 在动画开始的地方快然后慢
              8.LinearInterpolator   以常量速率改变
              9.OvershootInterpolator    向前甩一定值后再回到原来位置

        具体的效果用文字描述可能大家想象不出来,可自行写个示例用一用看看效果,会有更直观的感受。接下来,我们挑选几个看一看源码实现。         
LinearInterpolator        线性的插值器,就是匀速的插值器,也是动画默认的插值器,不设置就会默认选择它。执行的函数图如下:

        
[AppleScript] 纯文本查看 复制代码
/**
 * An interpolator where the rate of change is constant
 */
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

    public LinearInterpolator() {
    }

    public LinearInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return input;
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createLinearInterpolator();
    }
}

        主要关注getInterpolation这个方法,Linear就是线性,匀速的,所以方法直接把input的值返回,也就是动画的效果进度和时间的进度保持一致,匀速播放完毕。
BounceInterpolator
        再来看一个复杂一点的,这个效果也是非常常用的一个,就是小球自由落体掉下去然后弹起来,再落下去弹起来,逐渐停止。

[AppleScript] 纯文本查看 复制代码
/**
 * An interpolator where the change bounces at the end.
 */
@HasNativeInterpolator
public class BounceInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
    public BounceInterpolator() {
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public BounceInterpolator(Context context, AttributeSet attrs) {
    }

    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;
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createBounceInterpolator();
    }
}

        看源码,这个getInterpolation就是一个关于时间的分段函数,在时间的不同阶段函数体是不一样的,所以最终得到了这个效果。由此我们可以大胆的想象一下,如果我们自己定义类实现这个接口,然后实现getInterpolation方法,用我们自己的函数来控制,不就能自己来编写动画插值器了吗。这里我们放出material design里非常火的一张图片。

        这里有一大堆的动画插值器的函数图,每一个都非常实用,选择合适的插值器就能让动画做的更加细腻,用户体验更佳,所以如果我们能实现这些插值器,就差不多覆盖所有的使用场景了。那光看图也想不出来函数怎么实现啊,不要着急,我这里都准备好了,就在附件里面,自行取用吧。

Animation Interpolator.rar

3.49 KB, 下载次数: 1

售价: 1 黑马币  [记录]  [购买]

2 个回复

倒序浏览
山哥666  谢谢分享
回复 使用道具 举报
多谢分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马