Android開發藝術探索 - 第7章 Android動畫深入分析

Animation resources
Property Animation Overview

1.View動畫

  1. Tween補間動畫
    四種動畫效果,平移TranslateAnimation、縮放ScaleAnimation、旋轉RotateAnimation和透明度AlphaAnimation,xml中對應四種標籤的定義方式(res/anim/xxx.xml):
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@[package:]anim/interpolator_resource"
        android:shareInterpolator=["true" | "false"] >
        <alpha
            android:fromAlpha="float"
            android:toAlpha="float" />
        <scale
            android:fromXScale="float"
            android:toXScale="float"
            android:fromYScale="float"
            android:toYScale="float"
            android:pivotX="float"
            android:pivotY="float" />
        <translate
            android:fromXDelta="float"
            android:toXDelta="float"
            android:fromYDelta="float"
            android:toYDelta="float" />
        <rotate
            android:fromDegrees="float"
            android:toDegrees="float"
            android:pivotX="float"
            android:pivotY="float" />
        <set>
            ...
        </set>
    </set>
    
    • <set> 代表AniamtionSet類
      android:interpolator 插值器
      android:shareInterpolator 是否與子元素共享插值器
    • <alpha>
      android:fromAlpha
      android:toAlpha
    • <scale>
      android:fromXScale
      android:toXScale
      android:fromYScale
      android:toYScale
      android:pivotX 縮放中心
      android:pivotY 縮放中心
    • <translate>
      支持三種數據格式:-100100以%結尾,代表關於自身的比例;-100100以%p結尾,代表關於其父組件的比例;float值,絕對參數。
      android:fromXDelta
      android:toXDelta
      android:fromYDelta
      android:toYDelta
    • <rotate>
      android:fromDegrees
      android:toDegrees
      android:pivotX 旋轉中心,也支持三種數據格式:相對於父組件左邊緣的%p,相對於自身左邊緣的%,相對於自身左邊緣的x
      android:pivotY
    • 其他常用屬性:
      android:duration
      android:fillAfter 動畫結束後是否停留在結束位置
    • 應用動畫
    ImageView image = (ImageView) findViewById(R.id.image);
    Animation hyperspaceJump = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
    image.startAnimation(hyperspaceJump);
    
    • 自定義插值器
      通過xml創建自己的插值器,然後引用現有的插值器,並修改其屬性。如果不修改屬性,則其表現相當於原始的插值器。
    <?xml version="1.0" encoding="utf-8"?>
    <InterpolatorName xmlns:android="http://schemas.android.com/apk/res/android"
        android:attribute_name="value"
        />
    
  • <accelerateInterpolator>
    android:factor 加速度,默認1。
  • <anticipateInterpolator>
    android:tension 張力,默認2。
  • <anticipateOvershootInterpolator>
    android:tension
    android:extraTension 乘以tension,默認1.5。
  • <cycleInterpolator>
    android:cycles 循環次數,默認1。
  • <decelerateInterpolator>
    android:factor 減速度,默認1。
  • <overshootInterpolator>
    android:tension 張力,默認2。
  1. Frame幀動畫
    在xml中定義(res/drawable/xxx.xml),對應類AnimationDrawable。
    <?xml version="1.0" encoding="utf-8"?>
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:oneshot=["true" | "false"] >
        <item
            android:drawable="@[package:]drawable/drawable_resource_name"
            android:duration="integer" />
    </animation-list>
    
    • android:oneshot
      是否播放一次。
    • 使用
      <?xml version="1.0" encoding="utf-8"?>
      <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
          android:oneshot="false">
          <item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
          <item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
          <item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
      </animation-list>
      
      ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
      rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
      
      rocketAnimation = rocketImage.getBackground();
      if (rocketAnimation instanceof Animatable) {
          ((Animatable)rocketAnimation).start();
      }
      
  2. View動畫其他應用
    • LayoutAnimation
      作用於ViewGroup的子元素,常用於ListView。
      1. 定義LayoutAnimation
        <?xml version="1.0" encoding="utf-8"?>
        <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
            android:delay=""
            android:animationOrder=""
            android:animation=""/>
        
        android:delay 播放動畫開始前的延時
        android:animationOrder 動畫播放順序,normal/reverse/random
        android:animation 指定動畫
      2. 定義動畫
      3. 在爲ViewGroup設置android:layoutAnimation,指向定義的LayoutAnimation。
    • Activity切換動畫
      overridePendingTransition(int enterAnim, int exitAnim)
      在startActivity和finish之後調用。

2.屬性動畫

  1. 使用
    • xml定義,存放位置res/animator/xxx.xml
    <set
      android:ordering=["together" | "sequentially"]>
    
        <objectAnimator
            android:propertyName="string"
            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>
    
  • <set>
    android:ordering 動畫播放順序:sequentially/together(default)
  • <objectAnimator>
    android:propertyName 屬性名。如alpha/backgroundColor
    android:valueTo 需要指定。
    android:valueFrom 默認值通過getXX從target得到
    android:duration 默認300ms
    android:startOffset 調用start之後delay的時間
    android:repeatCount -1:無限循環;1:重複一次;0:不重複
    android:repeatMode 重複方式:reverse/repeat
    android:valueType intType/floatType,當animation color時不需要指定。
  • <animator>
    除了沒有propertyName,與objectAnimator相同。
  • 使用
    AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
        R.animator.property_animator);
    set.setTarget(myObject);
    set.start();
    
    • 代碼
    ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
    animation.setDuration(1000);
    animation.start();
    
    animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator updatedAnimation) {
            // You can use the animated value in a property that uses the
            // same type as the animation. In this case, you can use the
            // float value in the translationX property.
            float animatedValue = (float)updatedAnimation.getAnimatedValue();
            textView.setTranslationX(animatedValue);
        }
    });
    
    ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
    animation.setDuration(1000);
    animation.start();
    
  1. 插值器和估值器
    自定義插值器需要實現Interpolator或TimeInterpolator接口,自定義估值器需要實現TypeEvaluator接口。如果需要對除了int/float/Color之外的屬性做動畫,則一定需要實現自定義估值器。
  2. 動畫監聽
    • Animator.AnimatorListener:監聽動畫開始/停止/取消/重複
      onAnimationStart()
      onAnimationEnd()
      onAnimationRepeat()
      onAnimationCancel()
    • AnimatorListenerAdapter:AnimatorListener的空實現
    • ValueAnimator.AnimatorUpdateListener 如果使用的是ValueAnimator,則需要實現該接口
      onAnimationUpdate() 在動畫的每一幀回調
  3. 屬性動畫原理
    ValueAnimator調用start方法之後,在整個動畫的過程中,ValueAnimator會基於已經逝去的時間計算elapsed fraction;之後調用TimeInterpolator將elapsed fraction映射爲interpolated fraction;最後,基於start value,end value和interpolated fraction通過TypeEvaluator計算出當前的property value。ref
    ValueAnimator只實現了計算動畫屬性值的工作,將屬性值更新到target的過程需要自己完成;ObjectAnimator則在ValueAnimator基礎上,完成了設置屬性值的工作。所以前者有更大的靈活性,在使用後者時,一些注意事項:
    • 設置的屬性必須有其set方法,foo->setFoo。如果沒有set方法,有三種選擇:如果有權限,直接添加一個set方法;使用一個wrapper類包裝原始對象,然後設置set方法;使用ValueAnimator。
    • 如果參數中只指定了一個value,即沒有指定start value,則該屬性必須要有get方法,foo->getFoo
    • set方法和get方法操作的類型要一致。
  4. ViewPropertyAnimator
    因爲Android 3.0之前的View動畫的侷限性,屬性動畫得以引入。而對於View來說,屬性動畫得益於引入了相應的屬性:
    • translationX/translationY
    • rotation/rotationX/rotationY
    • scaleX/scaleY
    • pivotX/pivotY
    • x(left + translationX)/y(top + translationY)
    • alpha
      同時提供了更方便的API去實現View的屬性動畫:
    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 pvhX = PropertyValuesHolder.ofFloat("x", 50f);
    PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
    ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start();
    
    myView.animate().x(50f).y(100f);    // ViewPropertyAnimator
    

3.注意事項

  1. OOM問題->幀動畫
  2. 內存泄漏->屬性動畫的無限循環,在Activity退出之後要停止
  3. 硬件加速
  4. View動畫不能移動View本身,如果動畫完成後,setVisibility(GONE)失效,需要調用view.clearAnimation()清除動畫。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章