Android 属性动画

一:属性动画简介

    Android 属性动画是API 11引入的,更在的版本可以使用Nineoldandroids来实现,Nineoldandroids官方网站http://nineoldandroids.com。
    Nineoldandroids对属性动画做了兼容,在API 11之前的版本通过代理View动画来实现,因此在API 11之前的版本,本质还是View动画。Nineoldandroids的功能和系统原生的android,animation.*中类的功能用法完全一致。比较常用的几个动画类是:ValueAnimator,ObjectAnimator和AnimatorSet,其中ObjectAnimator继承自ValueAnimator,AnimatorSet是动画集合。
    先看几个小列子:

1.

ObjectAnimator.ofInt(myObjec,"width",500).setDuration(5000).start();
上面这句代码的作用就是使用ObjectAnimator属性动画来让myObjec这个对象的width属性在5s变为500px。

2.

ObjectAnimator.ofFloat(myObjec,"translationY", -myObjec.getHeight()).start();
上面这段代码的作用就是改变对象myObjec的translationY属性,让其沿着Y轴向上平移一段距离(myObjec的高度)。

3.

AnimatorSet set = new AnimatorSet();
        set.playTogether(
            ObjectAnimator.ofFloat(myObjec, "alpha", 1,0.5f,1),
            ObjectAnimator.ofFloat(myObjec, "rotationX", 0,180),
            ObjectAnimator.ofFloat(myObjec, "rotationY", 0,270),
            ObjectAnimator.ofFloat(myObjec, "translationY", 0,100),
            ObjectAnimator.ofFloat(myObjec, "translationX", 0,100),
            ObjectAnimator.ofFloat(myObjec, "rotation", 0,-270),
            ObjectAnimator.ofFloat(myObjec, "scaleX", 1,1.2f),
            ObjectAnimator.ofFloat(myObjec, "scaleY", 1,0.5f)
            );
        set.setDuration(5000).start();
上面代码的作用在5s内对View做了透明度,旋转,平移,缩放动画。

从上面3个小例子不难看出,对一个view使用属性动画的代码还是比较容易理解的,当然,属性动画也可以通过XML来定义。
需要定义在res/animator目录下面。其大概样式如下:
<?xml version="1.0" encoding="utf-8"?>  
<set xmlns:android="http://schemas.android.com/apk/res/android"  
    android:ordering="together" >  

    <objectAnimator  
        android:duration="1000"  
        android:propertyName="scaleX"  
        android:valueFrom="1"  
        android:valueTo="0.5" >  
    </objectAnimator>  
    <animator  
        android:duration="1000"  
        android:valueFrom="1"  
        android:valueTo="0.5" >  
    </animator>  

</set>

下面对标签说明下:
objectAnimator标签属性:

  • android:propertyName——表示属性动画的作用对象的属性名称;

  • android:duration——动画的时长;

  • android:valueFrom——表示属性的起始值;

  • android:valueTo——表示属性的结束值;

  • android:startOffset——动画的延迟时间;

  • android:repeatCount——动画的重复次数(默认值0,-1表示无限循环);

  • android:repeatMode——动画的重复模式(“repeat”表示连续重复,“reverse”表示逆向重复。);

  • android:valueType——表示android:propertyName所指属性的类型,有“intType”和“floatType”两个可选,分别表示属性的类型为整形和浮点型。(如果android:propertyName所指的属性为颜色,那么不需要指定android:valueType,系统会自动做处理)。

    使用XML定义的属性动画非常简单,代码大概如下:

 Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scale);  
 anim.setTarget(mMv);  
 anim.start();  

二:属性动画的监听器

属性动画提供了监听器用于监听动画的播放过程,主要有AnimatorUpdateListener和AnimatorListener。
AnimatorListener的定义如下:
public static Interface AnimatorListener{
        void onAnimationStart(Animator arg0);
        void onAnimationRepeat(Animator arg0);
        void onAnimationEnd(Animator arg0);
        void onAnimationCancel(Animator arg0);
        }

从定义中可以看出它可以监听动画的开始、结束、取消以及重复播放。使用起来也很简单因为系统提供了AnimatorListener的适配器。使用代码如下:

ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
        valueAnimator.addListener(new AnimatorListener() {

            @Override
            public void onAnimationStart(Animator arg0) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onAnimationRepeat(Animator arg0) {
                // TODO Auto-generated method stub  
            }

            @Override
            public void onAnimationEnd(Animator arg0) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onAnimationCancel(Animator arg0) {
                // TODO Auto-generated method stub
            }
        });

三:高级使用

首先先分析下属性动画的原理:
属性动画要求动画作用的对象提供该属性的set和get方法,属性动画根据外界传递的初始值和最终值,以动画的效果多次去调用set方法,没次传递给set方法的值都不一样,确切说是随着时间的推移,所传递的值越来越接近最终的值。那么想要给object的属性A做动画,那么必须要满足以下两个条件:
(1)object必须提供setA方法,如果动画开始的时候没有传递初始值,那么还要提供getA方法,因为系统要调用getA方法去获取初始值。
(2)object的setA对属性A所做的改变必须能够通过某种方式反映出来,比如会带来UI的变换之类的否则动画无效果。
例如,想给一个Button增加一个动画,使他的宽在5s内增加到500px。从Button的源码可以知道Button继承自TextView其getWidth获取的是其宽度,但是其setWidth是TextView和其子类的专属方法,它的作用不是设置View的宽度,而是设置TextView的最大宽度和最小宽度。其实就是,TextView的宽度对应XML中的android:layout_width属性,而TextView还有一个属性android:width,这个属性就对应了setWidth方法。所以通过setWidth无法改变控件的宽度。官方文档对于这种情况给出了3中解决方法:

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

这里发现第一种方案可行性极低,因为我们通常是没有修改这些组件的权限的。下面用代码来实现以下第二中方案,先看代码:

 private void performAnimate(){
        ViewWrapper wrapper = new ViewWrapper(button,button.getWidth());
        ObjectAnimator.ofInt(wrapper,"width",500).setDuration(5000).start();
    }

    private static class ViewWrapper{
        private View mTarget;
        private int mWidth;

        public ViewWrapper(View target,int width){
            mTarget = target;
            mWidth = width;
        }

        public int getWidth(){
            //return mTarget.getLayoutParams().width;
            return mWidth;
        }

        public void setWidth(int width){
            mTarget.getLayoutParams().width = width;
            mTarget.requestLayout();
        }

    }

从上面代码中不难看出我们首先是定义了一个类(ViewWrapper)来包装原始对象(Button),然后通过ViewWrapper的get和set方法来改变原对象的宽度。
对于第三种解决方案,同样先看代码:

private void performAnimate(final View target, final int start, final int end) {
        ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
        valueAnimator.addUpdateListener(new AnimatorUpdateListener() {

            // 持有一个IntEvaluator对象,方便下面估值的时候使用
            private IntEvaluator mEvaluator = new IntEvaluator();

            @Override
            public void onAnimationUpdate(ValueAnimator animator) {
                // 获得当前动画的进度值,整型,1-100之间
                int currentValue = (Integer) animator.getAnimatedValue();
                Log.d(TAG, "current value: " + currentValue);

                // 获得当前进度占整个动画过程的比例,浮点型,0-1之间
                float fraction = animator.getAnimatedFraction();
                // 直接调用整型估值器通过比例计算出宽度,然后再设给Button
                target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);
                target.requestLayout();
            }
        });

        valueAnimator.setDuration(5000).start();
    }

上面的代码,会在5s内将一个数从1变到100,然后动画的每一帧都会调用onAnimationUpdate方法,在这个方法内可以获取当前的值和当前值所占的比例,就可以计算出此刻的宽度是多少,例如时间过了一半,那么当前值应该是50,比例是0.5,假设Button的初始宽度是100px,最终宽度是500px,那么此时的Button应该增加了(500-100)*0.5=200,那么当前的宽度应该是100+200=300。

到此属性动画大概讲述了一遍。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值