Android 动画深入分析(三)——属性动画的高级使用及工作原理

一.前言

前面已经介绍过了逐帧动画,补间动画,和一些属性动画的简单使用,接下来介绍一下属性动画的高级使用及工作原理。
 
前面的知识:
Android 动画深入分析(一)——逐帧动画,补间动画
 
Android 动画深入分析(二)——属性动画的简单使用

 
属性动画可以对任意对象进行动画操作,接下来我们就使用任意对象来实现动画。

二. 对任意属性做动画

给Button加一个动画,让button的宽度从当前值增加到500px,即对button的width属性做动画。
用上篇文章属性动画来实现:

ObjectAnimator.ofInt(button,"width",500).setDuration(5000).start();

但是发现没有效果。
 
先说明一下属性动画的原理:属性动画要求动画作用的对象提供该属性的get和set方法,属性动画根据外界传递的该属性的初始值和最终值,以动画的效果去多次调用set方法,每次传递给set方法的值都不一样,准切来说是随着时间的推移,所传递的值越来越接近最终值。如果动画的时候没有传递初始值,那么还要提供get方法,因为系统要去获取属性的初始值。总结一下,我们对object的属性abc做动画,如果想让动画生效,要同时满足两个条件:

  1. object必须要提供setAbc方法,如果动画的时候没有传递初始值,那么还要提供getAbc方法。
  2. object的setAbc对属性abc所做出的改变必须通过某种方法反应出来,比如会带来UI的改变之类的。

在button的内部虽然提供了getWidth和setWidth方法,但是这个setWidth方法并不改变视图的大小,即不满足条件2
 
解决方法:

  1. 给你的对象加上get和set方法,如果有条件的话
  2. 用一个类来包装原始对象,间接提供get和set方法
  3. 采用ValueAnimator,监听动画过程,自己实现属性的改变

使用上面的方法解决这个问题,第一种没有权限就不做解释
 

2.用一个类来包装原始对象,间接提供get和set方法

public class ViewWrapper {
   
    private View mTarget;

    public ViewWrapper(View mTarget) {
   
        this.mTarget = mTarget;
    }
    public int getWidth(){
   
        return mTarget.getLayoutParams().width;
    }
    public void setWidth(int width){
   
        mTarget.getLayoutParams().width = width;
        mTarget.requestLayout();
    }
}

属性动画调用:

 ObjectAnimator.ofInt(new ViewWrapper(button),"width",500).setDuration(5000).start();

解释:这里的操作对象时new ViewWrapper(button),在使用ObjectAnimator处理width属性时,会去多次调用ViewWrapper类中的set方法,而在set方法中我们对width做了处理,使其宽改变,最终达到效果。

 

3.采用ValueAnimator,监听动画过程,自己实现属性的改变

performAnimate(button,button.getLayoutParams().width,500);


private void performAnimate(View view, int start, int end) {
   
        ValueAnimator valueAnimator = ValueAnimator.ofInt(1,100);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   
        
            private IntEvaluator intEvaluator = new IntEvaluator();
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
   
                //获取当前动画的进度值
                int currentValue = (Integer) animation.getAnimatedValue();

                //获取当前动画占整个动画的比例
                float fraction = animation.getAnimatedFraction();
                //调用整型估值器,通过比例算出宽度,然后设给View,当然这里也可直接自己算
                view.getLayoutParams().width = intEvaluator.evaluate(fraction,start,end);
                view.requestLayout();
            }
        });
        valueAnimator.setDuration(5000).start();
    }

 

三.TypeEvaluator(估值器)

TypeEvaluator的作用是根据当前属性改变的百分比来计算改变后的属性值。
系统预设的有IntEvaluator(针对整型属性),FloatEvaluator(针对浮点型属性),和ArgbEvaluator(针对Color属性)。上面采用ValueAnimator,监听动画过程,自己实现属性的改变就采用了估值器
 

FloatEvaluator的内部实现机制

我们来看一下FloatEvaluator的代码实现:

public class FloatEvaluator implements TypeEvaluator<Number> {
   
    public Float evaluate(float fraction, Number startValue, Number endValue) {
   
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }
}

可以看到,FloatEvaluator实现了TypeEvaluator接口,然后重写evaluate()方法。evaluate()方法当中传入了三个参数,第一个参数fraction非常重要,这个参数用于表示动画的完成度的,我们应该根据它来计算当前动画的值应该是多少,第二第三个参数分别表示动画的初始值和结束值。那么上述代码的逻辑就比较清晰了,用结束值减去初始值,算出它们之间的差值,然后乘以fraction这个系数,再加上初始值,那么就得到当前动画的值了。
 

自定义TypeEvaluator

ValueAnimator中还有一个ofObject()方法,是用于对任意对象进行动画操作的。但是相比于浮点型或整型数据,对象的动画操作明显要更复杂一些,因为系统将完全无法知道如何从初始对象过度到结束对象,因此这个时候我们就需要实现一个自己的TypeEvaluator来告知系统如何进行过度。
 
1.首先自定义一个类:

public class Point {
    private float x;
    private float y;
    public Point(float x, float y) {
        this.x = x;
        this.y = y;
    }
    public float getX() {
        return x;
    }
    public float getY() {
        return y;
    }
}

这个类有两个成员变量,x,y,我们的目标是让将Point1(实例对象)通过动画平滑过度到Point2(实例对象)
 
2.定义PointEvaluator,如下所示:

public class PointEvaluator implements TypeEvaluator{
   
 
    @Override
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值