android动画之interpolator和typeEvaluator用法详解手机开发

Interpolator (插值器)

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

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

结构图:

android动画之interpolator和typeEvaluator用法详解手机开发

常见的插值器:

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

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

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

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

  BounceInterpolator   动画结束的时候弹起

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

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

  LinearInterpolator   以常量速率改变

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

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

我们看一个效果

这里写图片描述

android动画之interpolator和typeEvaluator用法详解手机开发android动画之interpolator和typeEvaluator用法详解手机开发

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

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

 

代码链接:点击打开链接

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/5667.html

(0)
上一篇 2021年7月17日
下一篇 2021年7月17日

相关推荐

发表回复

登录后才能评论