属性动画高级用法之TypeEvaluator和Interpolator

来源:互联网 发布:华东师范大学知乎 编辑:程序博客网 时间:2024/06/06 23:57

1、Interpolator 插值器,控制动画的变化速率,就是通常描述的加速度,可以简单理解为变化的快慢,它是一个接口,实现类如下


从上面关系图可以看到,差值器最终实现的接口是TimeInterpolator,它的源码如下

public interface TimeInterpolator {    float getInterpolation(float input);}
参数input的值介于0和1,显示当前在动画中所经过的动画时间的动画值,0个代表开始和1个代表结

 1.1、下面是DecelerateInterpolator的源码,看下getInterpolation方法的实现,如果mFactor 等于1.0f就会执行

 result = (float)(1.0f - (1.0f - input) * (1.0f - input));
上面这行翻译过来就是抛物线函数 1-(1-x)*(1-x) ,它对应的二维坐标图如下。可以看到x的值在[0,1]之间直线与抛物线的切点交于横坐标的角度在变小,而这里的角度可以看做是加速度,因此DecelerateInterpolator做的是减速运动。其他的插值器原理类似,这里就不在描述。

 

public class DecelerateInterpolator implements Interpolator {    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 makes exaggerates the     *        ease-out effect (i.e., it starts even faster and ends evens slower)     */    public DecelerateInterpolator(float factor) {        mFactor = factor;    }        public DecelerateInterpolator(Context context, AttributeSet attrs) {        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.DecelerateInterpolator);        mFactor = a.getFloat(com.android.internal.R.styleable.DecelerateInterpolator_factor, 1.0f);        a.recycle();    }        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;    }      private float mFactor = 1.0f;}

1.2、自定义插值器

自定义插值器需要实现接口 Interpolator,代码很简单如下 ,先减速后加速,是一个抛物口朝上抛物线。

<span style="font-size:14px;">public class ParabolaInterpolator implements Interpolator {@Overridepublic float getInterpolation(float input) {return (2 * input - 1) * (2 * input - 1);}}</span>

2、TypeEvaluator估值器

系统自带的估值器有下面几种



下面是小球按照正玄曲线从屏幕左边移动到右边,效果图如下


在这里使用的正玄曲线曲线公式是(float) Math.sin((30 * fraction) - Math.PI/2)+1,翻译成数学公式就是sin(10πx-π/2)+1,取值范围是[0,2]。如果将公式放到自定义的TypeEvaluator里面,配合动画就可以实时返回y和x的坐标值。
正玄曲线图如下:



现在开始进行自定义view的绘制,实现小球移动

2.1 移动

这个比较简单,通过paint和canvas对象结合可以绘制一个小球,通过坐标改变然后刷新界面重新绘制就可以移动。

2.2 设置动画,获取坐标

采用属性动画,因为ValueAnimator对象可以传入一个TypeEvaluator<T>对象,通过上面知道TypeEvaluator可以计算出坐标值。

2.3 移动

可以设置动画监听器addUpdateListener,可以获取到当前坐标,在调用界面刷新。

废话不多说,下面是源码

<span style="font-size:14px;">public class MoveCircle extends View {//小球半径private int radius=30;//画笔private Paint mPaint;//保存小球移动过程中的坐标private PointF currentPointF;//高度和宽度private int halfHeight;private int width;public MoveCircle(Context context) {super(context);init();}public MoveCircle(Context context, AttributeSet attrs) {super(context, attrs);init();}private void init(){mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setColor(Color.BLUE);halfHeight = ToolUtils.getDisplayMetrics(getContext()).heightPixels/2;width = ToolUtils.getDisplayMetrics(getContext()).widthPixels;currentPointF = new PointF(radius,halfHeight);startAnimator();} @Overrideprotected void onDraw(Canvas canvas) {canvas.drawCircle(currentPointF.x, currentPointF.y, radius, mPaint);super.onDraw(canvas);}/** * 启动动画 */    private void startAnimator() {//使用估值器ValueAnimator,传入一个自定义PositionEvaluator,设置起点坐标,设置终点坐标        ValueAnimator animator = ValueAnimator.ofObject(                new PositionEvaluator(),new PointF(radius, halfHeight),new PointF(width-radius, halfHeight));//监听变化过程        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {            currentPointF = (PointF) animation.getAnimatedValue();            Log.i("tag"," onAnimationUpdate x: "+currentPointF.x+"   y: "+currentPointF.y);                invalidate();            }        });        // 设置加速插值器AccelerateInterpolator()        animator.setInterpolator(new AccelerateInterpolator());        animator.setStartDelay(200);//推迟启动200毫秒        animator.setDuration(10 * 1000).start();//启动    } }</span>


<span style="font-size:14px;">public class PositionEvaluator implements TypeEvaluator<PointF>{private PointF pointF;public PositionEvaluator() {pointF = new PointF();}@Overridepublic PointF evaluate(float fraction, PointF startValue, PointF endValue) {//以正玄曲线从左边运行到右边//x轴:直线运动float x = 0;if (fraction == 0) {x = startValue.x;} else {x = fraction * endValue.x;}// sin(30x-π/2)+1  //y轴:正玄曲线,公式  (float) Math.sin((30 * fraction) - Math.PI/2)+1,其范围是[0,2]float range = (float) Math.sin((30 * fraction) - Math.PI/2)+1;//小球纵坐标+波动范围float y = endValue.y + range*30;pointF.x = x;pointF.y = y;return pointF;} }</span>





0 0
原创粉丝点击