android曲线位移动画,Android动画学习Demo(3) 沿着贝塞尔曲线移动的Property Animation...

Property Animation中最重要,最基础的一个类就是ValueAnimator了。Property Animation利用ValueAnimator来跟踪记录对象属性已经变化了多长时间及当前这个时间点的值。android

而在ValueAnimator中,又封装了两个类:ide

1)TimeInterpolator,也称插值器,是来计算当前动画运动的一个跟时间有关系的比例因子。函数

2)TypeEvaluator,这个就是利用TimeInterpolator计算出来的因子来算出当前动画运行到的位置。学习

这样讲太抽象了,咱们仍是先用天然语言来描述一下整个动画的过程吧。动画

动画的原理,其实就是一帧帧的画面顺着时间顺序,在咱们眼中造成视觉残留的效果。因此在动画中,时间的概念是很重要的,只有时间的变化,才能造成动画效果。ui

0)动画准备开始,咱们在这里设置了一个动画的时长(duration),若是不设置的话,动画的时长就是300毫秒,每一个画面显示的时间是10ms。同时也设置了某个属性值在这个时间段中变化的起始值start和结束值end,意思就是说,在duration时间中,属性值要从start 变化到 end。lua

1)动画开始了,过了 t 时间,ValueAnimator会根据 t / duration 算出一个时间消逝的比例因子(elapsed fraction),意思就是说,如今时间到 t了,咱们假设总的时间的duration就是3t吧,那就是如今已通过了1/3时间了,那这个属性值也应该要变化到1/3了。spa

2)动画继续,如今到了2t了,那么如今动画时间已通过了2/3了,那么这个属性值是否是已经变化到2/3了呢。.net

3)如今到了3t了,动画结束了,属性值就已经从start变成end值了。

那么如今问题来了,若是都是这样算的话,那动画不就一直是很匀速的了吗?是的,若是用的是LinearInterpolator的话。

TimeInterpolator

TimeInterpolator就是用来改变咱们这个动画速度的这样一个类了。为何叫插值器呢?我理解就是,原本动画踩着时间点,一步一步走的挺好的,它硬生生在中间的插了些值进去,或者抽了一些值出去,让整条路变得很差走了,前面变然变上坡了,走起来就慢了,原本过去 t 时间以后,动画的画面也应该在1/3的位置了,可是路很差走,它就走不到1/3,而可能只走了1/4了,然后面是下坡,一激动,步伐就快了许多,又遇上去了,可是无论中间的路怎么变化,时间点一到,必定是刚恰好落在最终的位置上的。

Android中提供的Interpolator主要有九个:

1)AccelerateDecelerateInterpolator:先加速再减速。

2)AccelerateInterpolator:一直加速。

3)AnticipateInterpolator:先日后一下,再嗖的一声勇往直前。

4)AnticipateOvershootInterpolator:先日后一下,再一直往前超过终点,再往回收一下。

5)BounceInterpolator:最后像个小球弹几下。

6)CycleInterpolator:重复几回,感受就是环形进度条那种,具体我还没试过。

7)DecelerateInterpolator:一直减速。

8)LinearInterpolator:线性,这个就是咱们上面讲到的很均匀的了。

9)OvershootInterpolator:到了终点以后,超过一点,再往回走。有个参数能够定义,超过的力度。

这些Interpolator都是实现了TimeInterpolator接口的类,它们只须要实现一个方法:getInterpolation (float input),将这个input根据本身的需求从新计算这个比例

第一步: 当到了某时间t以后,ValueAnimator会算出某个比例 fraction = t / duration,而Interpolator会接收这个比例fraction,再调用其getInterpolation方法将这个比例因子从新计算一下,返回一个新的比例因子,好比LinearInterpolator实现的方法就是什么都不变,以下:

public float getInterpolation(float input) {

return input;

} 而 AccelerateDecelerateInterpolator 则会利用余弦函数的对称性变化计算这个比例因子,以下:

public float getInterpolation(float input) {

return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;

}

如上所述,经过第一步 Interpolator 的插值,咱们会获得一个比例因子,接下来就是要用到咱们的TypeEvaluator了。

TypeEvaluator

第二步: TypeEvaluator会接受第一步中算出来的比例因子,而后算出当前的属性的值,将其返回给ValuaAnimator,由ValueAnimator去设置对应属性的值。

好比,我本身写了一个BezierTypeEvaluator,根据时间的变化来让一个按钮沿着贝塞尔曲线移动,以下:

class BezierEvaluator implements TypeEvaluator{

@Override

public PointF evaluate(float fraction, PointF startValue,

PointF endValue) {

final float t = fraction;

float oneMinusT = 1.0f - t;

PointF point = new PointF();

PointF point0 = (PointF)startValue;

PointF point1 = new PointF();

point1.set(width, 0);

PointF point2 = new PointF();

point2.set(0, height);

PointF point3 = (PointF)endValue;

point.x = oneMinusT * oneMinusT * oneMinusT * (point0.x)

+ 3 * oneMinusT * oneMinusT * t * (point1.x)

+ 3 * oneMinusT * t * t * (point2.x)

+ t * t * t * (point3.x);

point.y = oneMinusT * oneMinusT * oneMinusT * (point0.y)

+ 3 * oneMinusT * oneMinusT * t * (point1.y)

+ 3 * oneMinusT * t * t * (point2.y)

+ t * t * t * (point3.y);

return point;

}

} 自定义TypeEvaluator,咱们必须实现其evaluate方法,目的就是计算出目前的对象对应属性的值,而它会接收三个参数,一个是上文中经过interpolator算出的比例,还有咱们在建立动画时设置的起始值和结束值。

ValueAnimator.AnimatorUpdateListener

既然咱们已经算出了在 t 时刻,对象的某个属性的值,那么咱们要把这个值从新设置到对象中,才可以起做用啊。因此ValueAnimator也提供了一个内部的Listener接口,其只有一个方法,就是获取TypeEvaluator计算出来的值,并设置给对应的属性,好比咱们Demo中的代码:

valueAnimator.addUpdateListener(new AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

PointF pointF = (PointF)animation.getAnimatedValue();

button.setX(pointF.x);

button.setY(pointF.y);

}

}); 咱们在这里改变Button的X坐标和Y坐标,从而改变其具体的位置。至于validate,而后引发从新绘制的过程,对于这些基本的属性,ValueAnimator已经帮咱们实现了。

下面,咱们看看效果图,而后再总结一下ValueAnimator的实现机制。

93bacf53326fd746e441e228e8ba0850.png

总的来讲,就是三步:

1)将时间的消逝 t 和时长 duration 的比例fraction,传给interpolator 算出一个新的fractionNew。

2)将这个fractionNew传给TypeEvaluator,算出对应属性的当前值animatedValue。

3)根据animatedValue,在AnimatorUpdateListener中更新属性的值。

说到这里,那为何咱们上一篇里面都是用ObjectAnimator呢,为何它不用AnimatorUpdateListener去更新值呢?

那是由于咱们在建立ObjectAnimator的时候,已经将对应的属性名称propertyName都先告诉它了,ObjectAnimator会根据这个propertyName去找它的set方法,从而去更新值,而这也是为何ObjectAnimator的对象必定要有对应属性的get/set方法的缘由。这是它的方便之处,但同时也是它的局限之处。

若是一个系统定义的对象的某个属性没有对应的get/set方法的时候,那咱们怎么办呢?

1)最简单的,就是去添加get/set方法,若是咱们有权限的话,但不少时候咱们没有。

2)给它添加一个包装类,引入一个get/set方法去设置原本的属性,来间接改变其值。

3)就是利用ValueAnimator,本身去实现其变更的逻辑了。

嗯,这一篇文章大概就是这样了,你们若是有兴趣了解Property Animation的应用的话,能够看一下

最后仍是要提醒一下,Property Animation是3.0之后才支持的,若是你们想在3.0以前去应用这些属性的话,能够去下载jake wharton的nineoldandroids包,基本上均可以直接将方法套上,不过据我实验,仍是有某些方法,好比 PropertyValuesHolder就会有些bug出现的。我把这个包也放在这里吧,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值