属性动画(Property Animation)

作者: 备忘君 | 来源:发表于2016-05-04 23:17 被阅读565次

    属性动画的特性

    1.Duration(持续时间)
    2.时间插着器(Time interpolation):指定这个属性的值变化的方式。比如,变化越来越快,或是越来越慢。
    3.重复的次数和方式(Repeat count and behavior):你可以指定动画是否重复播放、重复的次数、重复的方式(从头到尾正向重复还是从尾到头反向重复)
    4.动画集合(Animator sets):将多个动画组织成一个逻辑集合,你可以让这些动画同时播放,或是一个一个顺序播放,或是其他逻辑。
    5.帧刷新频率(Frame refresh delay):即,属性的值得刷新频率。系统默认10ms,不过实际刷新频率,还是又系统的繁忙程度和系统时钟的快慢来决定的。

    时间插值器(TimeInterpolator)

    一句话总结时间插值器的作用:根据当前的时间进度比,计算出当前动画进度比例。

    TimeInterpolator本身是一个接口,它的实现类决定了动画变化的速度。你如果不想让你的动画是线性匀速变化,比如加速或减速变化,就需要实现这个方法。

    //接口代码
    public interface TimeInterpolator { 
        float getInterpolation(float input);
    }
    

    getInterpolation()方法的参数:input = 过去的时间 / 总时间。表示动画的当前时间位置,0表示开始,1.0表示结束。
    getInterpolation()的返回值则表示经过插值计算之后的值,一般在0-1之间,不过,这个返回值可能存在小于0和大于1的情况,这是为了实现越界反弹等动画效果。

    线性插值器LinearInterpolator的getInterpolation()只是简单的将input返回,方法体如下

    public float getInterpolation(float input) {
        return input;
    }
    

    加速插值器AccelerateInterpolator的getInterpolation()默认情况下回返回input的平方。

    public float getInterpolation(float input) {
        if (mFactor == 1.0f) {
            return input * input;
        } else {
            return (float)Math.pow(input, mDoubleFactor);
        }
    }
    

    类型求值器(TypeEvaluator)

    TypeEvaluator根据当前时间点的动画进度,计算出属性当前时间点的值。

    在上面我们知道TimeInterpolator根据当前的时间进度比,计算出动画进度应有的比例。那么TypeEvaluator就是根据这个动画进度参数、属性初始值,属性最终值,就算出当前时间下的属性的值。

    //TypeEvaluator接口代码
    public interface TypeEvaluator<T> {
        //根据动画进度,属性起始值和结束值,计算出当前值
        public T evaluate(float fraction, T startValue, T endValue);
    }
    

    TypeEvaluator是用来计算属性值,它的实现类有IntEvaluator, FloatEvaluator, ArgbEvaluator等,分别用于不同类型的属性。比如你的属性是int类型的,则对应IntEvaluator

    //IntEvaluator的实现
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
    

    Property Animation 和 View Animation的区别

    1. View Animation 只能用于View及View的子类的对象;Property Animation则没有这样的限制
      2.View Animation限制较多,一些动画,只能用于没有background的view,否则会打不到预期效果;如,缩放一个view时,这是缩小了view的外观,她的background并没有改变,所以如果background不是透明的,则会露馅。
      3.View Animation只是简单的改变View的绘制,并不会改变View本身。比如,你将一个button从位置1移动到位置2,但是触发点击事件的位置还是在位置1。Property Animation这不会出现这种情况。
    2. View Animation 使用的代码较少,启动所花费的时间也短,如果View Animation能够达到你想要的效果,你同样可以继续使用它。你可以根据情况的不同,选择使用哪种动画。

    ValueAnimator

    举个栗子

    ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
    animation.setDuration(1000);
    animation.start();
    

    上面这段代码中,ValueAnimator在1000ms内,在0f-1f之间,不断地改变这个浮点类型的值,0f是开始值,1f是结束值。

    ValueAnimator有工厂方法ofInt()、ofFloat()、ofObject()用于不同的类型。

    对于自定义类型,你可以这样:

    ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
    animation.setDuration(1000);
    animation.start();
    

    在这段代码中,ValueAnimator在开始值startPropertyValue和结束值endPropertyValue之间,不断的计算属性值。

    上面的代码并没有真正作用到一个对象上,除了属性值的改变,你观察不到任何变化。如果你想达到当属性值变化的同时,让某个对象(外观、内容等任意)也随之改变,你需要为这个ValueAnimator设置Animation Listeners.当属性动画时间周期内发生重要事件,比如帧刷新,此Listener可以通过getAnimatedValue()得到这个属性在此时的值,然后根据这个值,去做相应的操作,比如移动控件的位置,改变大小等。

    ObjectAnimator

    ObjectAnimator是ValueAnimator的子类。其让属性动画作用于任何对象都变得很简单,而不再需要实现ValueAnimator.AnimatorUpdateListener,因为这个对象的属性会自动的刷新。

    举个栗子

    ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);
    anim.setDuration(1000);
    anim.start();
    

    ObjectAnimator会不断的改变对象foo的透明度。
    foo对象的类中必须有setAlpha(float alpha)成员函数

    ObjectAnimator注意事项

    1.动画作用于的目标对象的属性必须有set<propertyName>()形式的setter方法。ObjectAnimator通过这个方法更新此属性的值。
    2.如果你没有为参数values...提供起始值,比如,ObjectAnimator.ofFloat(foo, "alpha")或ObjectAnimator.ofFloat(foo, "alpha",1f)(提供一个值,则作为结束值),你必须提供getter方法,形如get<propertyName>(),如getAlpha();
    3.getter和setter方法的参数类型必须和ObjectAnimator.ofXXX(targetObject,"propName",values...)的values的类型相同。
    4.根据用于动画的属性的不同,你可能需要调用view的invalidate()方法强制在重绘view。你可以在onAnimationUpdate()中调用invalidate();比如,Drawable的color属性,只有当此Drawable重绘时才会引起屏幕刷新。

    Animation Listeners

    你可以用下面的Listener监听动画,一边在重要事件发生是,有所操纵。

    Animator.AnimatorListener
    ValueAnimator.AnimatorUpdateListener
    AnimatorListenerAdapter -- 用与代替Animator.AnimatorListener

    如果你不想实现AnimatorListener的所有方法,你可以使用AnimatorListenerAdapter代替,AnimatorListenerAdapter使用空方法实现了AnimatorListener的所有方法。

    举个栗子

    ValueAnimatorAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
    fadeAnim.setDuration(250);
    fadeAnim.addListener(new AnimatorListenerAdapter() {
        public void onAnimationEnd(Animator animation) {
            balls.remove(((ObjectAnimator)animation).getTarget());
        }
    }
    

    布局动画

    属性动画同样可以想应用于View那样方便的应用于ViewGroup。通过调用ViewGroup#setLayoutTransition(LayoutTransition)方法为其设置

    你可以通过使用LayoutTransition的方法[setAnimator()](http://developer.android.com/reference/android/animation/LayoutTransition.html#setAnimator(int, android.animation.Animator)),并传入一个 Animator和一个下面的常量(定义在LayoutTransition中)值作为参数,来定制用于ViewGroup的动画。

    • APPEARING
      指明这个动画是用于当某个条目显示出来时使用.
    • CHANGE_APPEARING
      指明当有条目显现时,这个动画用于其他item.
    • DISAPPEARING
      指明这个动画是用于当某个条目隐藏时使用.
    • CHANGE_DISAPPEARING
      指明当有条目隐藏时,这个动画用于其他item.

    你可以在ViewGroup的xml中添加android:animateLayoutchanges="true"来为ViewGroup指定默认动画。
    栗子

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:id="@+id/verticalContainer"
        android:animateLayoutChanges="true" />
    

    指定关键帧 Keyframes

    一个Keyframe对象有一个time/value对组成,用于指定在特定时间点,动画的状态。每一个关键帧都可以有它自己的插值器,用来控制前一个关键帧和此关键帧的关系。

    1. 你必须使用方法ofInt(), ofFloat(), 和ofObject()中的一个来获得一个关键帧实例。
    2. 然后调用PropertyValuesHolder的工厂方法[ofKeyframe()](http://developer.android.com/reference/android/animation/PropertyValuesHolder.html#ofKeyframe(android.util.Property, android.animation.Keyframe...))来获得一个PropertyValuesHolder对象。
    3. 然后,将PropertyValuesHolder对象作为ObjectAnimator.ofPropertyValuesHolder()方法的参数,即可构造出一个对象。

    栗子

    Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
    Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
    Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
    PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
    ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation);
    rotationAnim.setDuration(5000ms);
    

    相关文章

      网友评论

        本文标题:属性动画(Property Animation)

        本文链接:https://www.haomeiwen.com/subject/latrrttx.html