Android開發藝術探索 第7章 動畫深入分析 讀書筆記

Android動畫可以分3種:View動畫,幀動畫和屬性動畫;屬性動畫為API11的新特性,在低版本是無法直接使用屬性動畫的。
本章主要學習內容:

  1. View動畫以及自定義View動畫。
  2. View動畫的一些特殊使用場景。
  3. 對屬性動畫做了一個全面的介紹。
  4. 使用動畫的一些注意事項。

7.1 View動畫

  1. View動畫的四種變換效果對應著Animation的四個子類:TranslateAnimation(平移動畫)、ScaleAnimation(縮放動畫)、RotateAnimation(旋轉動畫)和AlphaAnimation(透明度動畫),他們即可以用代碼來動態創建也可以用XML來定義,推薦使用可讀性更好的XML來定義。
  2. <set>標簽表示動畫集合,對應AnimationSet類,它可以包含若干個動畫,并且他的內部也可以嵌套其他動畫集合。android:interpolator 表示動畫集合所采用的插值器,插值器影響動畫速度,比如非勻速動畫就需要通過插值器來控制動畫的播放過程。
    android:shareInterpolator表示集合中的動畫是否和集合共享同一個插值器,如果集合不指定插值器,那么子動畫就需要單獨指定所需的插值器或默認值。
  3. Animation通過setAnimationListener方法可以給View動畫添加過程監聽。
  4. 自定義View動畫只需要繼承Animation這個抽象類,并重寫initialize和applyTransformation方法,在initialize方法中做一些初始化工作,在applyTransformation中進行相應的矩形變換,很多時候需要采用Camera來簡化矩形變換過程。
  5. 幀動畫是順序播放一組預先定義好的圖片,類似電影播放;使用簡單但容易引發OOM,盡量避免使用過多尺寸較大的圖片。

7.2 View動畫的特殊使用場景

  1. LayoutAnimation作用于ViewGroup,為ViewGroup指定一個動畫,當他的子元素出場的時候都會具有這種動畫,ListView上用的多,LayoutAnimation也是一個View動畫。
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animationOrder="normal"
    android:delay="0.3" android:animation="@anim/anim_item"/>
//--- delay 表示動畫開始的時間延遲,比如子元素入場動畫的時間周期為300ms,
//那么0.5表示每個子元素都需要延遲150ms才開始播放入場動畫。
//--- animationOrder 表示子元素的動畫的順序,有三種選項:
//normal(順序顯示)、reverse(逆序顯示)和random(隨機顯示)。
//---1. android:animation 為子元素指定具體的入場動畫
//----------------------
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:shareInterpolator="true">
    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />
    <translate
        android:fromXDelta="300"
        android:toXDelta="0" />
</set>

使用LayoutAnimation

//--- 第一種方法、為需要的ViewGroup指定android:layoutAnimation屬性
//---這樣ViewGroup的子View就有出場動畫了
   <ListView
       android:id="@+id/lv"
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1"
       android:layoutAnimation="@anim/anim_layout"/>
//
//--- 第二種方法、通過LayoutAnimationController來實現
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listview.setLayoutAnimation(controller);
  1. Activity/Fragment的切換效果
    在startActivity(Intent)或finish()之后調用overridePendingTransition(int enterAnim,int exitAnim)方法。
    Fragment也可以添加切換動畫,通過FragmentTransaction中的
    setCustomAnimations()方法來添加;需考慮兼容性使用View動畫,屬性動畫是API11新引入的;

7.3屬性動畫

  1. 屬性動畫可以對任意對象的屬性進行動畫而不僅僅是View,動畫默認間隔300ms,默認幀率10ms/幀。在一個時間間隔內完成對象從一個屬性值到另一個屬性值的改變。
  2. 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指定的屬性表示顏色,則不需要指定該屬性。
  3. 實際開發中建議使用代碼來實現屬性動畫,代碼來實現比較簡單,而且很多時候一個熟悉的初始值無法提前知道,需在代碼中動態獲取。
7.3.2 理解插值器和估值器
  1. 時間插值器(TimeInterpolator)的作用是根據時間流逝的百分比來計算出當前屬性值改變的百分比,系統預置的有LinearInterpolator(線性插值器:勻速動畫),AccelerateDecelerateInterpolator(加速減速插值器:動畫兩頭慢中間快),DecelerateInterpolator(減速插值器:動畫越來越慢)。
  2. 估值器(TypeEvaluator)的作用是根據當前屬性改變的百分比來計算改變后的屬性值。系統預置有IntEvaluator 、FloatEvaluator 、ArgbEvaluator。
//整形估值器源碼
 /**
    * @param fraction   表示開始和結束值之間的比例
    * @param startValue  開始值         
    * @param endValue  結束值
    * @return  
    */
public class IntEvaluator implements TypeEvaluator<Integer> {
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}
  1. 插值器和估值器除了系統提供之外,我們還可以自定義。自定義插值器需要實現Interpolator或者TimeInterpolator;自定義估值器算法需要實現TypeEvaluator。
7.3.3屬性動畫的監聽器
public static interface AnimatorListener {
    void onAnimationStart(Animator animation); //動畫開始
    void onAnimationEnd(Animator animation); //動畫結束
    void onAnimationCancel(Animator animation); //動畫取消
    void onAnimationRepeat(Animator animation); //動畫重復播放
}
  1. 為了方便開發,系統提供了AnimatorListenerAdapter類,它是AnimatorListener的適配器類,可以有選擇的實現以上4個方法。
  2. AnimatorUpdateListener會監聽整個動畫的過程,動畫由許多幀組成的,每播放一幀,onAnimationUpdate就會調用一次。
7.3.4 對任意屬性做動畫
  1. 屬性動畫要求作用的對象提供該屬性的get和set方法,缺一不可。
  2. 如果你的對象沒有對應的get和set方法
  • 請給你的對象加上get和set方法,如果你有權限的話(如果直接使用系統的類,是無法加上的);
  • 用一個類來包裝原始對象,間接為其提供get和set方法;
//包裝View類 用于給屬性動畫調用 從而包裝了set get
public class ViewWrapper {
      private View target;
      public ViewWrapper(View target) {
          this.target = target;
      }
      public int getWidth() {
          return target.getLayoutParams().width;
      }
      public void setWidth(int width) {
          target.getLayoutParams().width = width;
          target.requestLayout();
      }
}
  • 采用ValueAnimator,監聽動畫過程,自己實現屬性的改變;
   /** 使用ValueAnimator 監聽動畫過程 自己實現屬性改變
     *
     * @param target 作用的View
     * @param start 動畫起始值
     * @param end 動畫終止值
     */
    private void startValueAnimator(final View target, final int start, final int end) {
        ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            private IntEvaluator mEvaluation = new IntEvaluator();//新建一個整形估值起 方便估值使用

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //獲得當前動畫的進度值 1~100之間
                int currentValue = (int) animation.getAnimatedValue();
                Log.e("Anim", "currentValue: " + currentValue);
                //獲得當前進度占整個動畫過程的比例,浮點型,0~1之間
                float fraction = animation.getAnimatedFraction();
                //調用估值器,通過比例計算出寬度 ,再設置給Button
                int targetWidth = mEvaluation.evaluate(fraction, start, end);
                target.getLayoutParams().width = targetWidth;
                target.requestLayout();
            }
        });
    }

7.3.5 屬性動畫的工作原理

通過反射調用get/set方法;屬性動畫需要運行在有Looper的線程中。


7.4 使用動畫的注意事項

  1. 使用幀動畫時,當圖片數量較多且圖片分辨率較大的時候容易出現OOM,需注意,盡量避免使用幀動畫。
  2. 使用無限循環的屬性動畫時,在Activity退出時及時停止,否則將導致Activity無法釋放從而造成內存泄露
  3. View動畫是對View的影像做動畫,并不是真正的改變了View的狀態,因此有時候會出現動畫完成后View無法隱藏(setVisibility(View.GONE)失效),這時候調用view.clearAnimation()清理View動畫即可解決。
  4. 不要使用px,使用px會導致不同設備上有不同的效果。
  5. View動畫是對View的影像做動畫,View的真實位置沒有變動,也就導致點擊View動畫后的位置觸摸事件不會響應,屬性動畫不存在這個問題。
  6. 使用動畫的過程中,使用硬件加速可以提高動畫的流暢度。
  7. 動畫在3.0以下的系統存在兼容性問題,特殊場景可能無法正常工作,需做好適配工作。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1 背景 不能只分析源碼呀,分析的同時也要整理歸納基礎知識,剛好有人微博私信讓全面說說Android的動畫,所以今...
    未聞椛洺閱讀 2,758評論 0 10
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,523評論 25 708
  • 提及農村,在我們的第一印象中是這樣的 孩子的重點在玩和幫父母干家務 他們的快樂很簡單,父母很多時間是在外打工,他們...
    冷_9825閱讀 419評論 2 1
  • “安生啊,你說這村口的王大媽都等了她男人三年了她男人也沒回來,我看啊,她男人怕是回不來咯。” 安生揚了揚眉頭,但是...
    導演i求平臺閱讀 143評論 0 0
  • 若苦能訴 尚還可撐 若難能助 尚還可解 一個人 獨當一面 遠在天涯 從最初的無措 到現今的自如 中間滋味 唯有自知 好在
    負零小子閱讀 149評論 0 0