生活随笔
收集整理的這篇文章主要介紹了
View工作原理(四)view的layout过程
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
剛過完自己的本命年,新的一年希望自己有個新的開始,祝自己在新的一年里一帆風順,同時也祝廣大的朋友們新年新氣象,收獲多多!
一、android中view的layout過程總概
Layout
過程其實就是父視圖按照子視圖的大小及布局參數(shù)將子視圖放在窗口的合適的位置上。
視圖的布局過程是從
ViewRoot對象調(diào)調(diào)用根視圖的layout()方法開始,接著layout()方法調(diào)用根視圖的onLayout()方法,onLayout()方法會對所包含的子視圖逐一執(zhí)行layout操作,如果子視圖是ViewGroup子類對象,則繼續(xù)調(diào)用子視圖的layout(),重復這一過程。如果子視圖是View子類對象,則在子視圖重載的onLayout()內(nèi)部只需要將自己布局到視圖中,不需要對子視圖進行layout操作,這樣一次layout過程結束。過程如下圖:
?
轉載請說明出處:http://blog.csdn.net/ff20081528/article/details/17784911
二、layout詳細過程
View中的layout()方法源碼(ViewGroup類繼承了View類,layout過程先從ViewGroup子類開始):
[java] view plaincopy
???????????????????????public?final?void?layout(int?l,?int?t,?int?r,?int?b)?{?????????boolean?changed?=?setFrame(l,?t,?r,?b);?????????if?(changed?||?(mPrivateFlags?&?LAYOUT_REQUIRED)?==?LAYOUT_REQUIRED)?{?????????????if?(ViewDebug.TRACE_HIERARCHY)?{?????????????????ViewDebug.trace(this,?ViewDebug.HierarchyTraceType.ON_LAYOUT);?????????????}???????????????onLayout(changed,?l,?t,?r,?b);?????????????mPrivateFlags?&=?~LAYOUT_REQUIRED;?????????}?????????mPrivateFlags?&=?~FORCE_LAYOUT;?????}??
?
a)?首先我們看這個方法的定義,用了關鍵字final,說明此方法是不可被重寫的,這樣也就保證了View的layout過程是不變的。四個參數(shù)看注釋,左、上、右、下分別相距父視圖的距離。
b)?調(diào)用setFrame(l,t,r,b)將位置保存起來,這些參數(shù)將保存到View內(nèi)部變量?(mLeft、mTop、mRight、mBottom)中。保存完變量前,會先對比這些參數(shù)是否和原來的相同,如果相同,則什么都不做,如果不同則進行重新賦值,并在賦值前給mPrivateFlags中添加DRAWN標識,同時調(diào)用invalidate()通知View系統(tǒng)原來占用的位置需要重繪。
c)?調(diào)用onLayout(),View中定義的onLayout()方法默認什么都不做,View系統(tǒng)提供onLayout()方法的目的是為了使系統(tǒng)包含的子視圖的父視圖能夠在onLayout()方法對子視圖進行位置分配,正因為如此,如果是父視圖,則必須重寫onLayout(),也正因為如此ViewGroup類才會把onLayout重載改成了abstract類型。
d)清除mPrivateFlags中的LAYOUT_REQUIRED標識,因為layout操作已經(jīng)完成。
上面提到的setFrame方法源碼如下:
[java] view plaincopy
protected?boolean?setFrame(int?left,?int?top,?int?right,?int?bottom)?{??????????boolean?changed?=?false;??????????if?(DBG)?{??????????????Log.d("View",?this?+?"?View.setFrame("?+?left?+?","?+?top?+?","??????????????????????+?right?+?","?+?bottom?+?")");??????????}??????????if?(mLeft?!=?left?||?mRight?!=?right?||?mTop?!=?top?||?mBottom?!=?bottom)?{??????????????changed?=?true;????????????????????????????int?drawn?=?mPrivateFlags?&?DRAWN;????????????????????????????invalidate();??????????????int?oldWidth?=?mRight?-?mLeft;??????????????int?oldHeight?=?mBottom?-?mTop;??????????????mLeft?=?left;??????????????mTop?=?top;??????????????mRight?=?right;??????????????mBottom?=?bottom;??????????????mPrivateFlags?|=?HAS_BOUNDS;??????????????int?newWidth?=?right?-?left;??????????????int?newHeight?=?bottom?-?top;??????????????if?(newWidth?!=?oldWidth?||?newHeight?!=?oldHeight)?{??????????????????onSizeChanged(newWidth,?newHeight,?oldWidth,?oldHeight);??????????????}??????????????if?((mViewFlags?&?VISIBILITY_MASK)?==?VISIBLE)?{????????????????????????????????????????????????????????????????????????????????????????????????????????????mPrivateFlags?|=?DRAWN;??????????????????invalidate();??????????????}????????????????????????????mPrivateFlags?|=?drawn;??????????????mBackgroundSizeChanged?=?true;??????????}??????????return?changed;??????}??
?View中的onLayout()方法如下:
[java] view plaincopy
protected?void?onLayout(boolean?changed,?int?left,?int?top,?int?right,?int?bottom)?{??????}??
而ViewGroup中的onLayout()方法如下:
[java] view plaincopy
@Override??????protected?abstract?void?onLayout(boolean?changed,??????????????int?l,?int?t,?int?r,?int?b);??
?
轉載請說明出處:http://blog.csdn.net/ff20081528/article/details/17784911?
因為ViewGroup中的onLayout()方法是一個抽象方法,所以下面我們用他的子類LinearLayout中的onLayout()方法來分析。源碼如下:
onlayout()方法:
[java] view plaincopy
@Override?????protected?void?onLayout(boolean?changed,?int?l,?int?t,?int?r,?int?b)?{?????????if?(mOrientation?==?VERTICAL)?{?????????????layoutVertical();?????????}?else?{?????????????layoutHorizontal();?????????}?????}??
layoutVertical()方法源碼:
[java] view plaincopy
void?layoutVertical()?{??????????final?int?paddingLeft?=?mPaddingLeft;??????????int?childTop?=?mPaddingTop;??????????int?childLeft;????????????????????final?int?width?=?mRight?-?mLeft;??????????int?childRight?=?width?-?mPaddingRight;????????????????????int?childSpace?=?width?-?paddingLeft?-?mPaddingRight;??????????final?int?count?=?getVirtualChildCount();??????????final?int?majorGravity?=?mGravity?&?Gravity.VERTICAL_GRAVITY_MASK;??????????final?int?minorGravity?=?mGravity?&?Gravity.HORIZONTAL_GRAVITY_MASK;??????????if?(majorGravity?!=?Gravity.TOP)?{?????????????switch?(majorGravity)?{?????????????????case?Gravity.BOTTOM:???????????????????????????????????????????????????????????????childTop?=?mBottom?-?mTop?+?mPaddingTop?-?mTotalLength;?????????????????????break;?????????????????case?Gravity.CENTER_VERTICAL:?????????????????????childTop?+=?((mBottom?-?mTop)??-?mTotalLength)?/?2;?????????????????????break;?????????????}??????????}??????????for?(int?i?=?0;?i?<?count;?i++)?{??????????????final?View?child?=?getVirtualChildAt(i);??????????????if?(child?==?null)?{??????????????????childTop?+=?measureNullChild(i);??????????????}?else?if?(child.getVisibility()?!=?GONE)?{??????????????????final?int?childWidth?=?child.getMeasuredWidth();??????????????????final?int?childHeight?=?child.getMeasuredHeight();??????????????????final?LinearLayout.LayoutParams?lp?=??????????????????????????(LinearLayout.LayoutParams)?child.getLayoutParams();??????????????????int?gravity?=?lp.gravity;??????????????????if?(gravity?<?0)?{??????????????????????gravity?=?minorGravity;??????????????????}??????????????????switch?(gravity?&?Gravity.HORIZONTAL_GRAVITY_MASK)?{??????????????????????case?Gravity.LEFT:??????????????????????????childLeft?=?paddingLeft?+?lp.leftMargin;??????????????????????????break;??????????????????????case?Gravity.CENTER_HORIZONTAL:??????????????????????????childLeft?=?paddingLeft?+?((childSpace?-?childWidth)?/?2)??????????????????????????????????+?lp.leftMargin?-?lp.rightMargin;??????????????????????????break;??????????????????????case?Gravity.RIGHT:??????????????????????????childLeft?=?childRight?-?childWidth?-?lp.rightMargin;??????????????????????????break;??????????????????????default:??????????????????????????childLeft?=?paddingLeft;??????????????????????????break;??????????????????}??????????????????childTop?+=?lp.topMargin;??????????????????setChildFrame(child,?childLeft,?childTop?+?getLocationOffset(child),??????????????????????????childWidth,?childHeight);??????????????????childTop?+=?childHeight?+?lp.bottomMargin?+?getNextLocationOffset(child);??????????????????i?+=?getChildrenSkipCount(child,?i);??????????????}??????????}??????}??
a)?LinearLayout中的子視圖有兩種布局方式,一個是縱向的,一個是橫向的,這里我們以縱向的分析。
b)?獲得子視圖的寬度。
c)?根據(jù)父視圖中的grarity屬性,來判斷子視圖的起始位置。
d) 開始for()循環(huán),為每個子視圖分配位置。對于每個子視圖首先取出子視圖的LayoutParams屬性,并且獲得gravity的值。根據(jù)gravity的值確定水平方向的起始位置,三種值分別為:LEFT,CENTER_HORIZONTAL和RIGHT.接著調(diào)用setChildFrame(),該方法內(nèi)部實際上就是調(diào)用child.layout()為子視圖設置布局位置。
《新程序員》:云原生和全面數(shù)字化實踐50位技術專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結
以上是生活随笔為你收集整理的View工作原理(四)view的layout过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。