android动画之interpolator和typeEvaluator用法详解

Interpolator (插值器)

我们在写动画的时候为了达到某种效果往往需要设置插值器,用来真实的模拟生活中的场景。

 Interpolator (插值器)被用来修饰动画效果,定义动画的变化率,可以使存在的动画效果accelerated(加速),decelerated(减速),repeated(重复),bounced(弹跳)等。

结构图:

常见的插值器:

 AccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢,在中间的时候加速

  AccelerateInterpolator  在动画开始的地方速率改变比较慢,然后开始加速

  AnticipateInterpolator 开始的时候向后然后向前甩

  AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值

  BounceInterpolator   动画结束的时候弹起

  CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线

  DecelerateInterpolator 在动画开始的地方快然后慢

  LinearInterpolator   以常量速率改变

  OvershootInterpolator    向前甩一定值后再回到原来位置

如果上面的插值器不满足你的要求,你可以自定义插值器。

我们看一个效果

这里我自定义了一个插值器,实现匀速的转动

public class MyInterpolator extends LinearInterpolator {
	private float factor;

	public MyInterpolator() {
		this.factor = 0.15f;
	}

	@Override
	public float getInterpolation(float input) {
		return (float) (Math.pow(2, -10 * input)
				* Math.sin((input - factor / 4) * (2 * Math.PI) / factor) + 1);
	}
}

接下来我们要说说Android属性动画的估值器。

TypeEvaluator(估值器)

TypeEvaluator(估值器):ValueAnimator.ofObject()函数来做动画效果的时候就会用到,作用是估算我们动画执行到什么程度,什么时间执行什么动画的一个类。估值器用到了TypeEvaluator这个接口:

public interface TypeEvaluator<t> {
 
    /**
     * @param fraction   The fraction from the starting to the ending values
     * @param startValue The start value.
     * @param endValue   The end value.
     * @return A linear interpolation between the start and end values, given the
     *         <code>fraction</code> parameter.
     */
    public T evaluate(float fraction, T startValue, T endValue);
 
}

这里有三个函数:fraction: 表示当前这段数值变化值得比例,startValue:表示当前这段数值变化的开始值,endValue: 表示当前这段数据变化的结束值。

估值器在哪里用得到呢,很多地方,举一个简单的例子,如用属性动画执行帧动画效果。

那么估值器是怎么工作的呢,我们来看下ValueAnimator的源码,其中在KeyframeSet类里有这么一个方法,这就是估值器工作的地方

public Object getValue(float fraction) {
        // Special-case optimization for the common case of only two keyframes
        if (mNumKeyframes == 2) {
            if (mInterpolator != null) {
                fraction = mInterpolator.getInterpolation(fraction);
            }
            return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),
                    mLastKeyframe.getValue());
        }
        if (fraction <= 0f) {
            final Keyframe nextKeyframe = mKeyframes.get(1);
            final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
            if (interpolator != null) {
                fraction = interpolator.getInterpolation(fraction);
            }
            final float prevFraction = mFirstKeyframe.getFraction();
            float intervalFraction = (fraction - prevFraction) /
                (nextKeyframe.getFraction() - prevFraction);
            return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),
                    nextKeyframe.getValue());
        } else if (fraction >= 1f) {
            final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
            final TimeInterpolator interpolator = mLastKeyframe.getInterpolator();
            if (interpolator != null) {
                fraction = interpolator.getInterpolation(fraction);
            }
            final float prevFraction = prevKeyframe.getFraction();
            float intervalFraction = (fraction - prevFraction) /
                (mLastKeyframe.getFraction() - prevFraction);
            return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
                    mLastKeyframe.getValue());
        }
        Keyframe prevKeyframe = mFirstKeyframe;
        for (int i = 1; i < mNumKeyframes; ++i) {
            Keyframe nextKeyframe = mKeyframes.get(i);
            if (fraction < nextKeyframe.getFraction()) {
                final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
                final float prevFraction = prevKeyframe.getFraction();
                float intervalFraction = (fraction - prevFraction) /
                    (nextKeyframe.getFraction() - prevFraction);
                // Apply interpolator on the proportional duration.
                if (interpolator != null) {
                    intervalFraction = interpolator.getInterpolation(intervalFraction);
                }
                return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
                        nextKeyframe.getValue());
            }
            prevKeyframe = nextKeyframe;
        }
        // shouldn't reach here
        return mLastKeyframe.getValue();
    }

在这之前有一个方法:

 void calculateValue(float fraction) {
        Object value = mKeyframes.getValue(fraction);
        mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
    }

调用到了getValue(),得到的值放在了mAnimatedValue里面,要通过PropertyValuesHolder类的getAnimatedValue()函数来得这个值

而这个函数在ValusAnimator中有调用。

void animateValue(float fraction) {
        fraction = mInterpolator.getInterpolation(fraction);
        mCurrentFraction = fraction;
        int numValues = mValues.length;
        for (int i = 0; i < numValues; ++i) {
            mValues[i].calculateValue(fraction);
        }
        if (mUpdateListeners != null) {
            int numListeners = mUpdateListeners.size();
            for (int i = 0; i < numListeners; ++i) {
                mUpdateListeners.get(i).onAnimationUpdate(this);
            }
        }
    }

Android系统内置了很多的估值器:

如下几种估值器 ArgbEvaluator, FloatArrayEvaluator, FloatEvaluator, IntArrayEvaluator, IntEvaluator, PointFEvaluator, RectEvaluator。

当然我们也可以自定义估值器,比我我们自定义一个实现字符从A_Z变化的估值器。

public class CalEvaluator implements TypeEvaluator<character> {
 
    @Override
    public Character evaluate(float fraction, Character startValue, Character endValue) {
        int startInt = (int) startValue;
        int endInt = (int) endValue;
        int cur = (int) (startInt + fraction * (endInt - startInt));
        return (char) cur;
    }
}

代码链接:点击打开链接

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏HT

HT for Web可视化QuadTree四叉树碰撞检测

QuadTree四叉树顾名思义就是树状的数据结构,其每个节点有四个孩子节点,可将二维平面递归分割子区域。QuadTree常用于空间数据库索引,3D的椎体可见区域...

3319
来自专栏数据结构与算法

BZOJ 2463: [中山市选2009]谁能赢呢?(智商)

Description 小明和小红经常玩一个博弈游戏。给定一个n×n的棋盘,一个石头被放在棋盘的左上角。他们轮流移动石头。每一回合,选手只能把石头向上,下,左,...

2956
来自专栏程序员互动联盟

网站上的验证码是怎么产生的?

目前,许多网站的会员登录时都要求输入验证码,尽管验证码的形式五花八门,但是所使用的原理基本是一样的,都是生成随机字符串,然后描绘成图片的形式输出。 验证码的...

3649
来自专栏GIS讲堂

Arcgis for JS之Cluster聚类分析的实现(基于区域范围的)

咱们书接上文,在上文,实现了基于距离的空间聚类的算法实现,在本文,将继续介绍空间聚类之基于区域范围的实现方式,好了,闲言少叙,先看看具体的效果:

1655
来自专栏阿凯的Excel

巧妙完成二维表的数据匹配

接下来我将每周分享一个广大网友向我提问的经典问题。 本周问题,如何对二维表进行匹配! 原表格! ? 备注:以上人名,均属虚构,如有雷同!说明有缘!!! 咳...

2833
来自专栏大大的微笑

java如何根据二进制流确定图片的类型

 为什么需要这样做? 因为仅仅通过后缀名我们并不能得知用户是否把图片的类型更改为其他类型. public enum ImageType { PNG('P','...

6756
来自专栏HansBug's Lab

3359: [Usaco2004 Jan]矩形

3359: [Usaco2004 Jan]矩形 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 8  Solv...

3596
来自专栏菩提树下的杨过

Flash/Flex学习笔记(48):反向运动学(下)

先要复习一下三角函数与余弦定理: 对于直角三角形,三边长a,b,c与三个角A,B,C的关系如下: ? 正弦函数: ? 余弦函数: ? 正切函数: ? 反正切函数...

24610
来自专栏儿童编程

Python的艺术玩法——“孔雀开屏”篇

本文用Python实现一个“孔雀开屏”的效果,Python也可以这么玩。下面是源码,注释里面的是不同画面的执行代码。

2082
来自专栏HT

HTML5实现3D和2D可视化QuadTree四叉树碰撞检测

QuadTree四叉树顾名思义就是树状的数据结构,其每个节点有四个孩子节点,可将二维平面递归分割子区域。QuadTree常用于空间数据库索引,3D的椎体可见区域...

2699

扫码关注云+社区

领取腾讯云代金券