属性动画高级用法之TypeEvaluator和Interpolator
2016-07-14 18:22
639 查看
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,代码很简单如下
,先减速后加速,是一个抛物口朝上抛物线。
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,可以获取到当前坐标,在调用界面刷新。
废话不多说,下面是源码
从上面关系图可以看到,差值器最终实现的接口是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>
相关文章推荐
- Gifski:一个跨平台的高质量 GIF 编码器
- 模仿动画的放大缩小容器
- jQuery 1.9.1源码分析系列(十五)动画处理之缓动动画核心Tween
- Android实现定制返回按钮动画效果的方法
- Android中ViewFlipper的使用及设置动画效果实例详解
- jQuery实现美观的多级动画效果菜单代码
- php判断GIF图片是否为动画的方法
- jQuery实现动画效果circle实例
- HTML5游戏引擎LTweenLite实现的超帅动画效果(附demo源码下载)
- 浅析JavaScript动画
- js排序动画模拟-插入排序
- javascript+HTML5的Canvas实现Lab单车动画效果
- 基于javascript实现漂亮的页面过渡动画效果附源码下载
- js实现按钮颜色渐变动画效果
- 超赞的jQuery图片滑块动画特效代码汇总
- jQuery实现连续动画效果实例分析
- 利用jquery制作滚动到指定位置触发动画
- jQuery实现的给图片点赞+1动画效果(附在线演示及demo源码下载)
- jQuery实现带有洗牌效果的动画分页实例
- jQuery动画效果相关方法实例分析