日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

View工作原理(四)view的layout过程

發布時間:2025/6/15 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 View工作原理(四)view的layout过程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
剛過完自己的本命年,新的一年希望自己有個新的開始,祝自己在新的一年里一帆風順,同時也祝廣大的朋友們新年新氣象,收獲多多!
一、android中view的layout過程總概
Layout過程其實就是父視圖按照子視圖的大小及布局參數將子視圖放在窗口的合適的位置上。 視圖的布局過程是從ViewRoot對象調調用根視圖的layout()方法開始,接著layout()方法調用根視圖的onLayout()方法,onLayout()方法會對所包含的子視圖逐一執行layout操作,如果子視圖是ViewGroup子類對象,則繼續調用子視圖的layout(),重復這一過程。如果子視圖是View子類對象,則在子視圖重載的onLayout()內部只需要將自己布局到視圖中,不需要對子視圖進行layout操作,這樣一次layout過程結束。過程如下圖: ?
轉載請說明出處:http://blog.csdn.net/ff20081528/article/details/17784911
二、layout詳細過程
View中的layout()方法源碼(ViewGroup類繼承了View類,layout過程先從ViewGroup子類開始): [java] view plaincopy
  • /**?
  • ????*?Assign?a?size?and?position?to?a?view?and?all?of?its?
  • ????*?descendants?
  • ????*?
  • ????*?<p>This?is?the?second?phase?of?the?layout?mechanism.?
  • ????*?(The?first?is?measuring).?In?this?phase,?each?parent?calls?
  • ????*?layout?on?all?of?its?children?to?position?them.?
  • ????*?This?is?typically?done?using?the?child?measurements?
  • ????*?that?were?stored?in?the?measure?pass().?
  • ????*?
  • ????*?Derived?classes?with?children?should?override?
  • ????*?onLayout.?In?that?method,?they?should?
  • ????*?call?layout?on?each?of?their?their?children.?
  • ????*?
  • ????*?@param?l?Left?position,?relative?to?parent?
  • ????*?@param?t?Top?position,?relative?to?parent?
  • ????*?@param?r?Right?position,?relative?to?parent?
  • ????*?@param?b?Bottom?position,?relative?to?parent?
  • ????*/??
  • ???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,說明此方法是不可被重寫的,這樣也就保證了Viewlayout過程是不變的。四個參數看注釋,左、上、右、下分別相距父視圖的距離。

    b)?調用setFrame(l,t,r,b)將位置保存起來,這些參數將保存到View內部變量?(mLeftmTopmRightmBottom)中。保存完變量前,會先對比這些參數是否和原來的相同,如果相同,則什么都不做,如果不同則進行重新賦值,并在賦值前給mPrivateFlags中添加DRAWN標識,同時調用invalidate()通知View系統原來占用的位置需要重繪。

    c)?調用onLayout(),View中定義的onLayout()方法默認什么都不做,View系統提供onLayout()方法的目的是為了使系統包含的子視圖的父視圖能夠在onLayout()方法對子視圖進行位置分配,正因為如此,如果是父視圖,則必須重寫onLayout(),也正因為如此ViewGroup類才會把onLayout重載改成了abstract類型。

    d)清除mPrivateFlags中的LAYOUT_REQUIRED標識,因為layout操作已經完成。

    上面提到的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;??
  • ????????????//?Remember?our?drawn?bit??
  • ????????????int?drawn?=?mPrivateFlags?&?DRAWN;??
  • ????????????//?Invalidate?our?old?position??
  • ????????????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)?{??
  • ????????????????//?If?we?are?visible,?force?the?DRAWN?bit?to?on?so?that??
  • ????????????????//?this?invalidate?will?go?through?(at?least?to?our?parent).??
  • ????????????????//?This?is?because?someone?may?have?invalidated?this?view??
  • ????????????????//?before?this?call?to?setFrame?came?in,?therby?clearing??
  • ????????????????//?the?DRAWN?bit.??
  • ????????????????mPrivateFlags?|=?DRAWN;??
  • ????????????????invalidate();??
  • ????????????}??
  • ????????????//?Reset?drawn?bit?to?original?value?(invalidate?turns?it?off)??
  • ????????????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;??
  • ????????//?Where?right?end?of?child?should?go??
  • ????????final?int?width?=?mRight?-?mLeft;??
  • ????????int?childRight?=?width?-?mPaddingRight;??
  • ????????//?Space?available?for?child??
  • ????????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:??
  • ???????????????????//?mTotalLength?contains?the?padding?already,?we?add?the?top??
  • ???????????????????//?padding?to?compensate??
  • ???????????????????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)?根據父視圖中的grarity屬性,來判斷子視圖的起始位置。 d) 開始for()循環,為每個子視圖分配位置。對于每個子視圖首先取出子視圖的LayoutParams屬性,并且獲得gravity的值。根據gravity的值確定水平方向的起始位置,三種值分別為:LEFT,CENTER_HORIZONTAL和RIGHT.接著調用setChildFrame(),該方法內部實際上就是調用child.layout()為子視圖設置布局位置。 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的View工作原理(四)view的layout过程的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。