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
期間有佈局請求
通過佈局監聽器來實現一系列順序操作
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.