Android佈局動畫梳理之LayoutTransition源碼追蹤


Android系統的佈局動畫可以按如下脈絡進行梳理

1、按時間點分類
     版本4.0之前可能沒有,4.0或以上有LayoutTransition,4.4.2或以上有scenes+transition

2、按動作劃分
     child自身的動畫
     child移動的動畫
     可能的組合
          被增刪的child的自身動畫
          被影響的其他child的自身動畫及移動動畫

3、按涉及的部件劃分
     ViewGroup或其子類
     LayoutTransition

4、需要梳理的問題
     被增刪的child的自身動畫-------就是單個view的動畫,這個無需梳理
     受影響的其他child的自身動畫
          何時、怎樣調用item的動畫?
          動畫模板是怎樣構建的?child怎樣拷貝這個模板的?
     受影響的其他child的移動動畫(重點)
          是不是有一個預佈局?
               留意一個監聽佈局改變的listener
          child移動動畫的初始值和結束值是怎樣計算的?又怎樣調用的?
          可能只有ViewGroup的增刪動作才觸發動畫?
          如果adapter的數據變化,又怎樣才能觸發動畫?
          4.4.2之後的框架是怎麼回事?
      其他child的自身動畫和移動動畫是怎樣疊加的?

5、相關知識點
     都有哪些佈局計算或操作?比如requestLayout()之類
     View體系中各個部件之間是怎樣通過設置Listener來互相通信及同步的?

6、梳理策略
     從ApiDemo裏面的LayoutTransition開始
     其後梳理由scenes+transition構成的Transitions framework



以下是從ViewGroup.addView()追蹤到LayoutTransition源碼的過程及結論

ViewGroup類

     addView(View child) / addView(View child, int index) / addView(View child, int width, int height)
          addView(View child, int index, LayoutParams params)
               addViewInner(View child, int index, LayoutParams params, boolean preventRequestLayout)
                    mTransition.addChild(this, child) //從這裏進入LayoutTransition類源碼
                    child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
                    onViewAdded(child);//這裏可能只是一個回調通知而已
                         mOnHierarchyChangeListener.onChildViewAdded(this, child);
                    childHasTransientStateChanged(child, true);

     removeView(View view) //和addView基本類似
          removeViewInternal(int index, View view)
               mTransition.removeChild(this, view);
               addDisappearingView(view);
               view.dispatchDetachedFromWindow();
               removeFromArray(index);
               onViewRemoved(view);
          requestLayout();

     結論
          在ViewGroup中應該只是一個增刪child及重新佈局的刷新操作
          沒有看到受影響的其他child的相關操作,這些可能都在LayoutTransition裏面


LayoutTransition類

     addChild(ViewGroup parent, View child)
          addChild(ViewGroup parent, View child, boolean changesLayout)
               runChangeTransition(parent, child, APPEARING);
                    loop: setupChangeAnimation(parent, changeReason, baseAnimator, duration, child);設置其他child的動畫
                         anim.setTarget(child);anim.setupStartValues();//設置當前child狀態爲動畫初始值
                              PropertyValuesHolder.setupValue(Object target, Keyframe kf) //通過反射機制獲取target的屬性值
                         View.OnLayoutChangeListener(){anim.setupEndValues();} //在重新佈局時獲取動畫結束值
                         parent.requestTransitionStart(LayoutTransition.this);//估計在這裏啓動動畫
                    loop: setupChangeAnimation((ViewGroup)parentParent, changeReason, parentAnimator, duration, tempParent);設置各級祖先層的動畫
               runAppearingTransition(parent, child);//這裏面實際上沒有什麼Transition,僅僅是啓動用戶設置的mAppearingAnim

     removeChild(ViewGroup parent, View child)
          removeChild(ViewGroup parent, View child, boolean changesLayout)
               runChangeTransition(parent, child, DISAPPEARING);//和addChild共用一個函數,只是選擇了另一個動畫
               runDisappearingTransition(parent, child);//裏面沒有Transition,直接啓動mDisappearingAnim

     結論
          增刪child導致其他child的佈局發生變化,下面是“其他child”的移動動畫構建流程
               在佈局修改前保存child狀態爲Transition動畫的初始值
               設置一個佈局改變監聽器
               在佈局改變後(可能在繪製前)保存child狀態爲Transition動畫的結束值
               啓動動畫
          其他child的自身動畫和移動動畫是怎樣疊加的?直接先後調用runChangeTransition和runAppearingTransition
          期間有佈局請求
          通過佈局監聽器來實現一系列順序操作



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章