欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android property aniamtion(属性动画)详解

程序员文章站 2024-03-24 13:03:28
...

本文将围绕属性动画的几个类(ValueAnimator,ObjectAnimator,AnimatorSet,PropertyValuesHolder 等等)详细介绍属性动的用法和原理,以及属性动画在xml资源的定义。
1.Animator
属性动画的基类,他是一个抽象类,只是定义了跟动画相关的规则,没有什么具体实现。我们都不会直接用到它。

2.ValueAnimator
Animator的子类,从类名就可猜到它的作用是某些“值”的变化,先来看看一个例子

//ofFloat初始化,0f 和 100f是动画的初始值和结束值
ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f); 
//设置动画时间
animation.setDuration(1000);
//设置监听,每隔一段时间(默认是10 ms,不同手机会有所不同),调一次onAnimationUpdate()方法
animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
       //获取当前值
       float animatedValue = (float)updatedAnimation.getAnimatedValue();
       //改变textView位置
       //textView.setTranslationX(animatedValue);
    }
});
//开始动画
animation.start();

从上面代码可以发现并没有什么动画的现象,是的ValueAnimator的作用就是如此,总的来说,这段代码的作用的就:
在1000ms内变化0f到100f,并且可以在onAnimationUpdate回调中得到实时值。如果想要用ValueAnimator做View的动画,可以在回调中处理如上的textView.setTranslationX(animatedValue)

3.TypeEvaluator
这个接口代表变化的值类型(如上面的ofFloat(0f, 100f)中就指定了变化的值类型是float),来看看TypeEvaluator的源码

public interface TypeEvaluator<T> {

    /**
     * @param fraction  动画时间百分百,代表当前处于那个时间点(即是 已过时间/总时间)
     * @param startValue 动画开始值,如上0f
     * @param endValue   动画结束值,如上100f
     * @return 返回动画当前值,所以不同的TypeEvaluator在evaluate中有不同的计算当前值的算法
     *        
     */
    public T evaluate(float fraction, T startValue, T endValue);
}

TypeEvaluator是一个接口,必须继承他来实现自己的TypeEvaluator,下面是android定义好的TypeEvaluator的算法

//float类型和TypeEvaluator
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);
    }
}

//int类型的TypeEvaluator
public class IntEvaluator implements TypeEvaluator<Integer> {

    //算法和float类型的一样
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}

//颜色类型的TypeEvaluator
public class ArgbEvaluator implements TypeEvaluator {
    private static final ArgbEvaluator sInstance = new ArgbEvaluator();


    public static ArgbEvaluator getInstance() {
        return sInstance;
    }


   //开启来比较负责,当时具体的算法不过管,只要明白这就是要改变颜色值是当前值的计算方法
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        int startInt = (Integer) startValue;
        int startA = (startInt >> 24) & 0xff;
        int startR = (startInt >> 16) & 0xff;
        int startG = (startInt >> 8) & 0xff;
        int startB = startInt & 0xff;

        int endInt = (Integer) endValue;
        int endA = (endInt >> 24) & 0xff;
        int endR = (endInt >> 16) & 0xff;
        int endG = (endInt >> 8) & 0xff;
        int endB = endInt & 0xff;

        return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
                (int)((startR + (int)(fraction * (endR - startR))) << 16) |
                (int)((startG + (int)(fraction * (endG - startG))) << 8) |
                (int)((startB + (int)(fraction * (endB - startB))));
    }
}

ValueAnimator中不同的静态实例化方法就内部就是用了不同的TypeEvaluator
ValueAnimator ofInt(TypeEvaluator evaluator, Object… values)//利用IntEvaluator算法
ValueAnimator ofFloat(int… values)//利用FloatEvaluator算法
ValueAnimator ofArgb(int… values)//利用ArgbEvaluator值类型算法
ValueAnimator ofObject(TypeEvaluator evaluator, Object… values)//传入自定义的FloatEvaluator
其中的变化值是一个可变参数(比如传了0,100表示从0到100变化;传了0,50,100表示从0到50变化,再从50到100变化;传了30,10,60表示从30到10变化,再从10到60变化。只传一个值代表结束值)

4.Interpolator
插值器,和上一篇属性动画的插值器一样代表变化的快慢,如加速变化,减速变化等等。TimeInterpolator接口源码

public interface TimeInterpolator {
    该接口定义类插值器规则,input的值在01之间代表时间百分百,返回值代表在当前时间的变化值的百分百(说白了就是这个时候变化到哪了),返回值可以是大于1或小于0(可以超越开始值和结束值,比如AnticipateInterpolator这个插值器,开始是会往回拉一下再往前走)。
    float getInterpolation(float input);
}

实现这个接口并覆写getInterpolation就可以自定义Interpolator了,下面是android定义好的Interpolator
AccelerateDecelerateInterpolator
AccelerateInterpolator
AnticipateInterpolator
AnticipateOvershootInterpolator
BounceInterpolator
CycleInterpolator
DecelerateInterpolator
LinearInterpolator
OvershootInterpolator
具体效果自己试下就知道了, ValueAnimator中setInterpolator(TimeInterpolator value)用于设置插值器。

5.ObjectAnimator
ObjectAnimator类是ValueAnimator的子类,他不像ValueAnimator要监听onAnimationUpdate来时view执行动画,它要传要执行动画的对象(不一定是view对象)即可,因为ObjectAnimator内部已经实现好了onAnimationUpdate。ObjectAnimator是属性最主要的类,因为在它上才体现属性的变化(ValueAnimator只是值的变化)。来看看怎么用吧。

//textView:要改变的属性的对象,指定对象的translationX属性名,后面是一个可变参数,和ValueAnimator类似
ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();

ObjectAnimator对属性的改变必须遵循下面的规则才有效
1.指定对象中必须要有指定属性的以驼峰命名的set方法(textView对象中必须要有setTranslationX方法)
2.如果后面的可变参数值传一个,则指定对象中必须要有指定属性的以驼峰命名的get方法(textView对象中必须要有getTranslationX方法)
3.以上两点的get的参数类型和set方法的返回值必须和ofXXX方法的类型相同(setTranslationX方法的参数类型,getTranslationX的返回必须和ofFloat类型相同,即float类型)

6. AnimatorSet
属性集合,可以同时或先后执行多个属性动画

AnimatorSet bouncer = new AnimatorSet();
//执行squashAnim1后执行bounceAnim
bouncer.play(bounceAnim).before(squashAnim1);
//同时执行squashAnim1后执行squashAnim2
bouncer.play(squashAnim1).with(squashAnim2);
//执行squashAnim1后执行bounceAnim
bouncer.play(bounceAnim).after(squashAnim1);
//调用strart方法上面添加的动画才会执行
animatorSet.start();

AnimatorSet的几个方法play,before,after,with的参数都是Animator对象,并将同时都返回原来的AnimatorSet。

7.Keyframe和PropertyValuesHolder
Keyframe包含了一个时间和值的键值对,代表某一时刻对应的值应该是多少,并将不用的Keyframe可以设置不同的Interpolator

//和ObjectAnimator一样Keyframe有三种类型:int float Object
//fraction为时间百分比,value为对应时刻的值
Keyframe.ofInt(float fraction, int value)
Keyframe.ofFloat(float fraction, floatvalue)
Keyframe.ofIObject(float fraction, Object value)

PropertyValuesHolder可以把多个Keyframe和指定属性集成起来,然后把集成好的PropertyValuesHolder传给指定对象使用。

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
//根据需要可以跟KeyFrame设置Interpolator
//kf0.setInterpolator(TimeInterpolator interpolator);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
//集成kf0,kf1,kf3,并传入rotation属性名
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
利用ofPropertyValuesHolder方法把PropertyValuesHolder和target对象关联起来生成ObjectAnimator对象
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000);
//执行动画
rotationAnim.start();

其实ObjectAnimator的ofXXX方法内部就是通过PropertyValuesHolder实现的,PropertyValuesHolder有对应的ofXXX方法。

8.属性动画在view控件上的使用
要让控件执行动画,有下面的几种方法
1.通过上的知识我们可以通过ValueAnimator设置监听来改变控件位置,但这样做比较麻烦。
2.利用ObjectAnimator出入指定view和属性,这个可以,那么view具体有那些属性可以执行动画的呢,有下面几个:
translationX , translationY: 平移x坐标y坐标,执行动画后对应控件的getLeft,getRight,getTop,getBottom返回值依然不会改变,但点击是热区是变了。
rotation, rotationX, rotationY:旋转,这个旋转属性是3d效果的
scaleX , scaleY: 缩放属性
pivotX ,pivotY:
x ,y:和translationX ,translationY效果一样只是,x属性值 = translationX 属性值 + getLeft返回值,y同理
alpha: 淡入淡出
看下例子

//直接使用ObjectAnimator 和AnimatorSet 
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

//使用PropertyValuesHolder 
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();

//只是最简单的方法View的animate()可以返回一个ViewPropertyAnimator对象,通过他我可以直接调用
//上面列出的view的属性的对应方法来执行动画,ViewPropertyAnimator可以设置动画时间和Interpolator
myView.animate().x(50f).y(100f);

9.在res资源文件中定义属性动画
和上一篇的视图动画不同,属性动画要放到res/animator路径下,在xml下以下的标签对应不同的类对象
ValueAnimator - <animator>
ObjectAnimator -<objectAnimator>
AnimatorSet - <set>

<set
  android:ordering=["together" | "sequentially" 代表同事执行还是顺序执行,默认为together]>

    <objectAnimator
        android:propertyName="属性名称"
        android:duration="int动画时间"
        android:valueFrom="开始值,只能是float | int | color"
        android:valueTo="结束值,只能是float | int | color"
        android:startOffset="int"
        android:repeatCount="int重复次数"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]/>

    <animator
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]/>

    <set>
        ...
    </set>
</set>

例子,在res/animator新建resproperty_animator.xml文件

<set android:ordering="sequentially">
    <set>
        <objectAnimator
            android:propertyName="x"
            android:duration="500"
            android:valueTo="400"
            android:valueType="intType"/>
        <objectAnimator
            android:propertyName="y"
            android:duration="500"
            android:valueTo="300"
            android:valueType="intType"/>
    </set>
    <objectAnimator
        android:propertyName="alpha"
        android:duration="500"
        android:valueTo="1f"/>
</set>

在代码中获取该动画

AnimatorSet set =(AnimatorSet)AnimatorInflater.loadAnimator(myContext,R.anim.property_animator);
//一定要用setTarget方法把动画设置到相应对象中
set.setTarget(myObject);
set.start();
相关标签: android