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

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 {
		@Override
		public 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();
	}
 
	@Override
	protected 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();
	}
	@Override
	public 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>





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值