前言
前些天研究自定義控件特意研究了下UI的繪制流程
1.首先說下Activity加載后的顯示的View圖
2.然后我們從setContentView(R.layout.activity_main)入手,調用了Activity中的
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);//1
initWindowDecorActionBar();
}
3.getWindow()拿到的是Window的實現類PhoneWindow
4,然后我們看PhoneWindow中的源碼的setContentView?
--------------------------------------------------------------------------------------
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();//在這里創建了一個DecorView(繼承自FrameLayout)2
}
……
mLayoutInflater.inflate(layoutResID, mContentParent);//初始化我們自己的布局 ?6
}
------------------------------------------------------------------------------
//decorView的具體創建過程
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();//生成一個DecorView 3
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);//得到布局文件 4
}
----------------------------------------------------------------------------------------
protected ViewGroup generateLayout(DecorView decor) {//進行加載布局得到decorview中包含title和我們contentview的布局 ?5
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
}
----------------------------------------------------------------------------------
由此我們可以看出Activity加載View的流程是getWindow().setContentView(layoutResID)-->
installDecor()-->generateDecor()生成一個DecorView對象-->generateLayout(mDecor)得到DecorView加載的包括title和我們自己寫的布局的也就是rootview-->generateLayout(DecorView decor)得到rootView-->mLayoutInflater.inflate(layoutResID, mContentParent)加載我們自己的布局
View的繪制
1.View的繪制執行measure,layout,draw三個執行流程
View類中
? ? ? ? ? ? measure:測量自己多大,如果是ViewGroup的話會同時測量子控件
? ? ? ? ? ?layout:擺放子控件的位置
? ? ? ? ? ?draw:繪制
從View.java類的源碼中看到:
1.view的requestLayout()方法開始,遞歸不斷的往上找父容器,最終找到DecorView
2.執行DecorView的ViewRootImp類中的performTransversal()方法
3.performTranversal(){
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
performDraw();
}
然后執行相應的measure,layout.draw方法,當是Viewgroup會調用相應的view的measure,layout,draw,當是View的時候調用measure,layout,draw然后執行想用onmeasure,onlayout,ondraw來進行相應的繪制
再說一下View的measure的測量規格MeasureSpec
1.mode
? ? ? ? ? ? ? 1)EXACTLY:精確的,例如我們寫的一個確定值50dp
? ? ? ? ? ? ? 2)AT_MOST:根據父容器當前的大小,結合你指定的尺寸參考值來考慮你應該是多大尺寸,需要計算(Match_parent,wrap_content就是屬于這種)
? ? ? ? ? ? ? 3)UPSPECIFIED:最多的意思。根據當前的情況,結合你制定的尺寸參考值來考慮,在不超過父容器給你限定的只存的前提下,來測量你的一個恰好的內容尺寸。用的比較少,一般見于ScrollView,ListView(大小不確定,同時大小還是變的。會通過多次測量才能真正決定好寬高。)
2.value:寬高的值