Android Animator的使用(一)

在Android 中,实现一个View的动画有两种方式Animation和Aniamtor,在Android3.0以后,推荐使用Animator实现动画效果,下面简单比较下Animator和Animation的区别

Animation实现原理

在每次进行绘图的时候,通过对整块画布的矩阵进行变换,从而实现一种视图坐标的移动,但实际上其在 View 内部真实的坐标位置及其他相关属性始终恒定.

Note: 这个机制会导致这样的问题, 一个View已经通过Animation移动位置了,但是他的点击事件仍然处于原来的位置,这个问题可以使用Animator解决

Animation的优点

1. 版本兼容

不得不说,相对于 Animation,Animator 的版本兼容性还是太差,直到 Android3.0才开始出现的 Animator, 是无法满足目前开发环境2.x 的兼容支持的,而且在 android 官方的 support 包中也没有对于低版本的 Animator 进行支持,所以单从版本兼容来看, Animator 还是不够的,不过这是系统历史原因,我们只能接受.

2.实现效率

同样的,这也是 Animator 的一个缺点,由于 Animator 是直接通过设置对象的 setter,getter 方法,来起到动画显示效果的,所以为了满足对任意对象调用正确方法,Animator 使用了 Java 反射机制, 而 Animation 则是直接通过代码对矩阵进行处理,所以就效率这一方面而言, Animator比不上 Animation

Animator的实现原理

Animator 动画的实现机制说起来其实更加简单一点,因为他其实只是计算动画开启之后,结束之前,到某个时间点得时候,某个属性应该有的值,然后通过回调接口去设置具体值,其实 Animator 内部并没有针对某个 view 进行刷新,来实现动画的行为,动画的实现是在设置具体值的时候,方法内部自行调取的类似 invalidate 之类的方法实现的.也就是说,使用 Animator ,内部的属性发生了变化.

Animator的优点

1. 适用性

在上一个分析中,我们看到了由于 Animator 使用了反射机制导致其效率偏低,但是这也带来了他适用的对象范围的增加, Animation 仅对 View 这一种对象有用,但是 Animator 可以设置任意对象的属性,使其在某段时间内进行变化

2. 使用效果

相信大家平时使用 Animation 的时候,都有发现当正在进行平移移动,或者动画结束后,但位置发生改变的时候,你点击之前的位置,点击效果仍然存在,这就是因为 View 在内部的坐标位置其实没有发生改变,而如果使用 Animator 进行位移变换,那么你的点击位置就会随着动画效果发生相应改变,所以即使你正处在动画过程中,你也可以去点击按钮得到你想要的效果.

相关API

Duration动画的持续时间,默认300ms。

Time interpolation:时间差值,乍一看不知道是什么,但是我说LinearInterpolator、AccelerateDecelerateInterpolator,大家一定知道是干嘛的了,定义动画的变化率。

Repeat count and behavior:重复次数、以及重复模式;可以定义重复多少次;重复时从头开始,还是反向。

Animator sets: 动画集合,你可以定义一组动画,一起执行或者顺序执行。

Frame refresh delay:帧刷新延迟,对于你的动画,多久刷新一次帧;默认为10ms,但最终依赖系统的当前状态;基本不用管。
相关的类

ObjectAnimator 动画的执行类,后面详细介绍

ValueAnimator 动画的执行类,后面详细介绍

AnimatorSet 用于控制一组动画的执行:线性,一起,每个动画的先后执行等。

AnimatorInflater 用户加载属性动画的xml文件

TypeEvaluator 类型估值,主要用于设置动画操作属性的值。

TimeInterpolator 时间插值.

Animator的简单使用

1. 使用属性动画实现平移

// 让文字下滑
// 此时View的属性已经发生变化
ObjectAnimator down = ObjectAnimator.ofFloat(mTvText, "translationY", -100, 0);
down.setDuration(2000);
down.start();

此处对比Animation的实现
还必须使用setFillAfter(true)让动画停留在原处

// 使用Animation实现
// 此时点击事件仍停留在原处
Animation downAnim = new TranslateAnimation(0, 0, 0, 200);
downAnim.setFillAfter(true);
downAnim.setDuration(2000);
mTvText.startAnimation(downAnim);

2. 可以添加UpdateListener来监听动画因子数值的变化

// 文字翻转
ObjectAnimator rotateX = ObjectAnimator.ofFloat(mTvText, "rotationX", 0, 360);
rotateX.setDuration(2000);
rotateX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        // 属性动画执行时,会回调这个监听器
        // 如果你的属性没有触发重绘,那你可以在这里加上invalidate()或postInvalidate()
        Log.d(TAG, "onAnimationUpdate: value=" + animation.getAnimatedValue()
                + "fraction=" + animation.getAnimatedFraction());
    }
});

3.使用PropertyValueHolder来实现多个动画的效果

这里也可以通过AnimaiorSet来实现,一会介绍

/**
* 使用PropertyValueHolder实现多个效果的动画
*/
PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0, 100);
PropertyValuesHolder leftX = PropertyValuesHolder.ofFloat("translationX", 0, 100);
PropertyValuesHolder downY = PropertyValuesHolder.ofFloat("translationY", 0, 100);
ObjectAnimator prop = ObjectAnimator.ofPropertyValuesHolder(mTvText, alpha, leftX, downY);
prop.setDuration(3000);
prop.start();

4.使用ValueAnimator实现动画效果

ValueAnimator可以说是动画的核心,ObjectAnimator继承自这个类,任何对属性值的操作也是通过它来完成的,但是ValueAnimator不与任何属性绑定,只能通过UpdateListener回调中完成相应的动画

/**
* 使用valueAnimator实现动画
*/
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 500);
valueAnimator.setTarget(mTvText);
valueAnimator.setDuration(2000);

/**
* valueAnimator 必须使用updateListener进行接收数据
* ValueAnimator不跟属性进行绑定
*/
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
       // 在数值变化监听器中实现动画变换
       mTvText.setTranslationX((Float) animation.getAnimatedValue());
   }
});

valueAnimator.start();

5. 自定义估值器

通过setEvaluator()设置自定义估值器,可以实现ValueAnimator对任意自定义的类型取值,下面是一个实现自有落体效果的例子,这里自定义了一个针对PointF的估值器

/**
 * 如果ValueAnimator返回的时自定义的类型,那么需要自定义估值器
 * 通过自定义估值器,可以实现在任意时间取值,实现数值的变化
 */
ValueAnimator va2 = new ValueAnimator();
va2.setObjectValues(new PointF(0, 0));
va2.setDuration(3000);
/**
 * 新的数据类型只与时间有关
 * 自定义估值器
 */
va2.setEvaluator(new TypeEvaluator<PointF>() {

    @Override
    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
        Log.d(TAG, "evaluate: fraction=" + fraction
                + " startValue=" + startValue + " endValue=" + endValue);
        PointF pointF = new PointF();
        // 自定义计算值
        pointF.x = 200 * fraction * 3;
        pointF.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);
        return pointF;
    }
});
va2.start();
va2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        PointF pointF = (PointF) animation.getAnimatedValue();
        mTvText.setX(pointF.x);
        mTvText.setY(pointF.y);
    }
});

6.使用AnimatorSet实现多个动画同时播放

与前面的PropertyValuesHolder类似,这个也能实现多个动画同时缩放,但是这个更灵活

/**
 * 使用AnimatorSet实现动画同时播放
 */
ObjectAnimator scaleX = ObjectAnimator.ofFloat(mTvText, "scaleX", 1f, 2f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(mTvText, "scaleY", 1f, 2f);
// AnimatorSet
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(2000);
animatorSet.setInterpolator(new LinearInterpolator());
// 两个动画同时执行
animatorSet.play(scaleX).with(scaleY);
/*
    animSet.play(anim1).with(anim2);
    animSet.play(anim2).with(anim3);
    animSet.play(anim4).after(anim3);
*/
animatorSet.start();

Note: 使用动画不会造成重新布局,它的X,Y属性并没有发生变化,变化的是View的动画属性,如translationX,但是View的形状也依赖于这些动画属性

这里写图片描述

可以看见,View已经移下去了,但是他的布局并没有发生变化,合理使用动画,一定程度能解决反复重新布局的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值