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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android角落 不妨再看LinearLayout

發布時間:2024/4/13 Android 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android角落 不妨再看LinearLayout 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文首發于github,是我所在的組LittleFriendsGroup的一個源碼分析項目哦,如果您感興趣,也可以去認領一篇文章寫寫你的觀點。

聲明.本項目源碼基于Api 23

1.談談LinearLayout

Android的常用布局里,LinearLayout屬于使用頻率很高的布局。RelativeLayout也是,但相比于RelativeLayout每個子控件都需要給上ID以供另一個相關控件擺放位置來說,LinearLayout兩個方向上的排列規則在明顯垂直/水平排列情況下使用更加方便。

同時,出于性能上來說,一般而言功能越復雜的布局,性能也是越低的(不考慮嵌套的情況下)。

相比于RelativeLayout無論如何都是兩次測量的情況下,LinearLayout只有子控件設置了weight屬性時,才會有二次測量,其余情況都是一次。

另外,LinearLayout的高級用法除了weight,還有divider,baselineAligned等用法,雖然用的不常見就是了。

以下是LinearLayout相比于其他布局所擁有的特性:

屬性值類型描述備注
orientationint作為LinearLayout必須使用的屬性之一,支持縱向排布或者水平排布子控件
weightSumfloat指定權重總和缺省值為1.0
baselineAlignedboolean基線對齊
baselineAlignedChildIndexint該LinearLayout下的view以某個繼承TextView的View的基線對齊
measureWithLargestChildboolean當值為true,所有帶權重屬性的View都會使用最大View的最小尺寸
divider(需要配合showDividers使用)drawable in java/reference in xml如同您常在ListView使用一樣,為LinearLayout添加分割線[api>11] 同時如果是自己建立的drawable,請指定size

【注意】divider附加屬性為showDividers(middle|end|beginning|none):

  • middle 在每兩項之間添加分割線
  • end 在整體的最后一項添加分割線
  • beginning 在整體的首項添加分割線
  • none 無

本篇主要針對LinearLayout垂直方向的測量、weight和divider進行分析,其余屬性因為比較冷門,因此不會詳說


2.使用方法

對于LinearLayout的使用,相信您閉著眼睛都能寫出來,因此這里就略過了。


3.源碼分析

源碼分析階段主要針對這幾個地方:

  • measure流程
  • weight的計算

后兩者的主要工作其實都是被包含在measure里面的,因此對于LinearLayout來說,最重要的,依然是measure.

3.1 measure

在LinearLayout的onMeasure()里面,所有的測量都根據mOrientation這個int值來進行水平或者垂直的測量計算。

我們都知道,java中int在初始化不分配值的時候,都是默認的0,因此如果我們不指定orientation,measure則會按照水平方向來測量【水平orientation=0/垂直orientation=1】

接下來我們主要看看measureVertical方法,了解了垂直方向的測量之后,水平方向的也就不難理解了,為了篇幅,我們主要分析垂直方向的測量。

measureVertical方法除去注釋,大概200多行,因此我們分段分析。

方法主要分為三大塊:

  • 一大堆變量
  • 一個主要的for循環來不斷測量子控件
  • 其余參數影響以及根據是否有weight再次測量
3.1.1

一大堆變量

為何這里要說說變量,因為這些變量都會極大的影響到后面的測量,同時也是十分容易混淆的,所以這里需要貼一下。

void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {// mTotalLength作為LinearLayout成員變量,其主要目的是在測量的時候通過累加得到所有子控件的高度和(Vertical)或者寬度和(Horizontal)mTotalLength = 0;// maxWidth用來記錄所有子控件中控件寬度最大的值。int maxWidth = 0;// 子控件的測量狀態,會在遍歷子控件測量的時候通過combineMeasuredStates來合并上一個子控件測量狀態與當前遍歷到的子控件的測量狀態,采取的是按位相或int childState = 0;/*** 以下兩個最大寬度跟上面的maxWidth最大的區別在于matchWidthLocally這個參數* 當matchWidthLocally為真,那么以下兩個變量只會跟當前子控件的左右margin和相比較取大值* 否則,則跟maxWidth的計算方法一樣*/// 子控件中layout_weight<=0的View的最大寬度int alternativeMaxWidth = 0;// 子控件中layout_weight>0的View的最大寬度int weightedMaxWidth = 0;// 是否子控件全是match_parent的標志位,用于判斷是否需要重新測量boolean allFillParent = true;// 所有子控件的weight之和float totalWeight = 0;// 如您所見,得到所有子控件的數量,準確的說,它得到的是所有同級子控件的數量// 在官方的注釋中也有著對應的例子// 比如TableRow,假如TableRow里面有N個控件,而LinearLayout(TableLayout也是繼承LinearLayout哦)下有M個TableRow,那么這里返回的是M,而非M*N// 但實際上,官方似乎也只是直接返回getChildCount(),起這個方法名的原因估計是為了讓人更加的明白,畢竟如果是getChildCount()可能會讓人誤認為為什么沒有返回所有(包括不同級)的子控件數量final int count = getVirtualChildCount();// 得到測量模式final int widthMode = MeasureSpec.getMode(widthMeasureSpec);final int heightMode = MeasureSpec.getMode(heightMeasureSpec);// 當子控件為match_parent的時候,該值為ture,同時判定的還有上面所說的matchWidthLocally,這個變量決定了子控件的測量是父控件干預還是填充父控件(剩余的空白位置)。boolean matchWidth = false;boolean skippedMeasure = false;final int baselineChildIndex = mBaselineAlignedChildIndex; final boolean useLargestChild = mUseLargestChild;int largestChildHeight = Integer.MIN_VALUE;} 復制代碼

這里有很多變量和值,事實上,直到現在,我依然沒有完全弄明白這些值的意義。

在這一大堆變量里面,我們主要留意的是三個方面:

  • mTotalLength:這個就是最終得到的整個LinearLayout的高度(子控件高度累加及自身padding)
  • 三個跟width相關的變量
  • weight相關的變量

3.1.2

測量

通過for循環不斷的得到子控件然后根據自己的定義進行賦值,這就是LinearLayout測量里面最重要的一步。

這里的代碼比較長,去掉注釋后有100行左右,因此這里采取重要地方注釋結合文字描述來分析。

void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {// ...接上面的一大堆變量for (int i = 0; i < count; ++i) {final View child = getVirtualChildAt(i);if (child == null) {// 目前而言,measureNullChild()方法返回的永遠是0,估計是設計者留下來以后或許有補充的。mTotalLength += measureNullChild(i);continue;}if (child.getVisibility() == GONE) {// 同上,返回的都是0。// 事實上這里的意思應該是當前遍歷到的View為Gone的時候,就跳過這個View,下一句的continue關鍵字也正是這個意思。// 忽略當前的View,這也就是為什么Gone的控件不占用布局資源的原因。(畢竟根本沒有分配空間)i += getChildrenSkipCount(child, i);continue;}// 根據showDivider的值(before/middle/end)來決定遍歷到當前子控件時,高度是否需要加上divider的高度// 比如showDivider為before,那么只會在第0個子控件測量時加上divider高度,其余情況下都不加if (hasDividerBeforeChildAt(i)) {mTotalLength += mDividerWidth;}final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)child.getLayoutParams();// 得到每個子控件的LayoutParams后,累加權重和,后面用于跟weightSum相比較totalWeight += lp.weight;// 我們都知道,測量模式有三種:// * UNSPECIFIED:父控件對子控件無約束// * Exactly:父控件對子控件強約束,子控件永遠在父控件邊界內,越界則裁剪。如果要記憶的話,可以記憶為有對應的具體數值或者是Match_parent// * AT_Most:子控件為wrap_content的時候,測量值為AT_MOST。// 下面的if/else分支都是跟weight相關if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {// 這個if里面需要滿足三個條件:// * LinearLayout的高度為match_parent(或者有具體值)// * 子控件的高度為0// * 子控件的weight>0// 這其實就是我們通常情況下用weight時的寫法// 測量到這里的時候,會給個標志位,稍后再處理。此時會計算總高度final int totalLength = mTotalLength;mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);skippedMeasure = true;} else {// 到這個分支,則需要對不同的情況進行測量int oldHeight = Integer.MIN_VALUE;if (lp.height == 0 && lp.weight > 0) {// 滿足這兩個條件,意味著父類即LinearLayout是wrap_content,或者mode為UNSPECIFIED// 那么此時將當前子控件的高度置為wrap_content// 為何需要這么做,主要是因為當父類為wrap_content時,其大小實際上由子控件控制// 我們都知道,自定義控件的時候,通常我們會指定測量模式為wrap_content時的默認大小// 這里強制給定為wrap_content為的就是防止子控件高度為0.oldHeight = 0;lp.height = LayoutParams.WRAP_CONTENT;}/**【1】*/// 下面這句雖然最終調用的是ViewGroup通用的同名方法,但傳入的height值是跟平時不一樣的// 這里可以看到,傳入的height是跟weight有關,關于這里,稍后的文字描述會著重闡述measureChildBeforeLayout(child, i, widthMeasureSpec, 0, heightMeasureSpec,totalWeight == 0 ? mTotalLength : 0);// 重置子控件高度,然后進行精確賦值if (oldHeight != Integer.MIN_VALUE) {lp.height = oldHeight;}final int childHeight = child.getMeasuredHeight();final int totalLength = mTotalLength;// getNextLocationOffset返回的永遠是0,因此這里實際上是比較child測量前后的總高度,取大值。mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +lp.bottomMargin + getNextLocationOffset(child));if (useLargestChild) {largestChildHeight = Math.max(childHeight, largestChildHeight);}}if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {mBaselineChildTop = mTotalLength;}if (i < baselineChildIndex && lp.weight > 0) {throw new RuntimeException("A child of LinearLayout with index "+ "less than mBaselineAlignedChildIndex has weight > 0, which "+ "won't work. Either remove the weight, or don't set "+ "mBaselineAlignedChildIndex.");}boolean matchWidthLocally = false;// 還記得我們變量里又說到過matchWidthLocally這個東東嗎// 當父類(LinearLayout)不是match_parent或者精確值的時候,但子控件卻是一個match_parent// 那么matchWidthLocally和matchWidth置為true// 意味著這個控件將會占據父類(水平方向)的所有空間if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) {matchWidth = true;matchWidthLocally = true;}final int margin = lp.leftMargin + lp.rightMargin;final int measuredWidth = child.getMeasuredWidth() + margin;maxWidth = Math.max(maxWidth, measuredWidth);childState = combineMeasuredStates(childState, child.getMeasuredState());allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;if (lp.weight > 0) {weightedMaxWidth = Math.max(weightedMaxWidth,matchWidthLocally ? margin : measuredWidth);} else {alternativeMaxWidth = Math.max(alternativeMaxWidth,matchWidthLocally ? margin : measuredWidth);}i += getChildrenSkipCount(child, i);}} 復制代碼

在代碼中我注釋了一部分,其中最值得注意的是measureChildBeforeLayout()方法。這個方法將會決定子控件可用的剩余分配空間。

measureChildBeforeLayout()最終調用的實際上是ViewGroup的measureChildWithMargins(),不同的是,在傳入高度值的時候(垂直測量情況下),會對weight進行一下判定

假如當前子控件的weight加起來還是為0,則說明在當前子控件之前還沒有遇到有weight的子控件,那么LinearLayout將會進行正常的測量,若之前遇到過有weight的子控件,那么LinearLayout傳入0。

那么measureChildWithMargins()的最后一個參數,也就是LinearLayout在這里傳入的這個高度值是用來干嘛的呢?

如果我們追溯下去,就會發現,這個函數最終其實是為了結合父類的MeasureSpec以及child自身的LayoutParams來對子控件測量。而最后傳入的值,在子控件測量的時候被添加進去。

protected void measureChildWithMargins(View child,int parentWidthMeasureSpec, int widthUsed,int parentHeightMeasureSpec, int heightUsed) {final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin+ widthUsed, lp.width);final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin+ heightUsed, lp.height);child.measure(childWidthMeasureSpec, childHeightMeasureSpec);} 復制代碼

在官方的注釋中,我們可以看到這么一句:

  • @param heightUsed Extra space that has been used up by the parent vertically (possibly by other children of the parent)

事實上,我們在代碼中也可以很清晰的看到,在getChildMeasureSpec()中,子控件需要把父控件的padding,自身的margin以及一個可調節的量三者一起測量出自身的大小。

那么假如在測量某個子控件之前,weight一直都是0,那么該控件在測量時,需要考慮在本控件之前的總高度,來根據剩余控件分配自身大小。而如果有weight,那么就不考慮已經被占用的控件,因為有了weight,子控件的高度將會在后面重新賦值。


3.2 weight

3.2.1

weight的再次測量

在上面的代碼中,LinearLayout做了針對沒有weight的工作,在這里主要是確定自身的大小,然后再針對weight進行第二次測量來確定子控件的大小。

我們接著看下面的代碼:

void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {//...接上面// 下面的這一段代碼主要是為useLargestChild屬性服務的,不在本文主要分析范圍,略過if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {mTotalLength += mDividerHeight;}if (useLargestChild &&(heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {mTotalLength = 0;for (int i = 0; i < count; ++i) {final View child = getVirtualChildAt(i);if (child == null) {mTotalLength += measureNullChild(i);continue;}if (child.getVisibility() == GONE) {i += getChildrenSkipCount(child, i);continue;}final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)child.getLayoutParams();// Account for negative marginsfinal int totalLength = mTotalLength;mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));}}// Add in our paddingmTotalLength += mPaddingTop + mPaddingBottom;int heightSize = mTotalLength;// Check against our minimum heightheightSize = Math.max(heightSize, getSuggestedMinimumHeight());// Reconcile our calculated size with the heightMeasureSpecint heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);heightSize = heightSizeAndState & MEASURED_SIZE_MASK;} 復制代碼

上面這里是為weight情況做的預處理。

我們略過useLargestChild 的情況,主要看看if處理外的代碼。在這里,我沒有去掉官方的注釋,而是保留了下來。

從中我們不難看出heightSize做了兩次賦值,為何需要做兩次賦值。

因為我們的布局除了子控件,還有自己本身的background,因此這里需要比較當前的子控件的總高度和背景的高度取大值。

接下來就是判定大小,我們都知道測量的MeasureSpec實際上是一個32位的int,高兩位是測量模式,剩下的就是大小,因此heightSize = heightSizeAndState & MEASURED_SIZE_MASK;作用就是用來得到大小的精確值(不含測量模式)

接下來我們看這個方法里面第二占比最大的代碼:

void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {//...接上面//算出剩余空間,假如之前是skipp的話,那么幾乎可以肯定是有剩余空間(同時有weight)的int delta = heightSize - mTotalLength;if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {// 限定weight總和范圍,假如我們給過weighSum范圍,那么子控件的weight總和受此影響float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;mTotalLength = 0;for (int i = 0; i < count; ++i) {final View child = getVirtualChildAt(i);if (child.getVisibility() == View.GONE) {continue;}LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();float childExtra = lp.weight;if (childExtra > 0) {// 全篇最精華的一個地方。。。。擁有weight的時候計算方式,ps:執行到這里時,child依然還沒進行自身的measure// 公式 = 剩余高度*(子控件的weight/weightSum),也就是子控件的weight占比*剩余高度int share = (int) (childExtra * delta / weightSum);// weightSum計余weightSum -= childExtra;// 剩余高度delta -= share;final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,mPaddingLeft + mPaddingRight +lp.leftMargin + lp.rightMargin, lp.width);if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) {int childHeight = child.getMeasuredHeight() + share;if (childHeight < 0) {childHeight = 0;}child.measure(childWidthMeasureSpec,MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));} else {child.measure(childWidthMeasureSpec,MeasureSpec.makeMeasureSpec(share > 0 ? share : 0,MeasureSpec.EXACTLY));}childState = combineMeasuredStates(childState, child.getMeasuredState()& (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));}final int margin = lp.leftMargin + lp.rightMargin;final int measuredWidth = child.getMeasuredWidth() + margin;maxWidth = Math.max(maxWidth, measuredWidth);boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&lp.width == LayoutParams.MATCH_PARENT;alternativeMaxWidth = Math.max(alternativeMaxWidth,matchWidthLocally ? margin : measuredWidth);allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;final int totalLength = mTotalLength;mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));}mTotalLength += mPaddingTop + mPaddingBottom;} // 沒有weight的情況下,只看useLargestChild參數,如果都無相關,那就走layout流程了,因此這里忽略else {alternativeMaxWidth = Math.max(alternativeMaxWidth,weightedMaxWidth);if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {for (int i = 0; i < count; i++) {final View child = getVirtualChildAt(i);if (child == null || child.getVisibility() == View.GONE) {continue;}final LinearLayout.LayoutParams lp =(LinearLayout.LayoutParams) child.getLayoutParams();float childExtra = lp.weight;if (childExtra > 0) {child.measure(MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),MeasureSpec.EXACTLY),MeasureSpec.makeMeasureSpec(largestChildHeight,MeasureSpec.EXACTLY));}}}} } 復制代碼

3.2.2

weight的兩種情況

這次我的注釋比較少,主要是因為需要有一大段的文字來描述。

在weight計算方面,我們可以清晰的看到,weight為何是針對剩余空間進行分配的原理了。 我們打個比方,假如現在我們的LinearLayout的weightSum=10,總高度100,有兩個子控件(他們的height=0dp),他們的weight分別為2:8。

那么在測量第一個子控件的時候,可用的剩余高度為100,第一個子控件的高度則是100*(2/10)=20,接下來可用的剩余高度為80

我們繼續第二個控件的測量,此時它的高度實質上是80*(8/8)=80

到目前為止,看起來似乎都是正確的,但關于weight我們一直有一個疑問:**就是我們為子控件給定height=0dp和height=match_parent時我們就會發現我們的子控件的高度比是不同的,前者是2:8而后者是調轉過來變成8:2 **

對于這個問題,我們不妨繼續看看代碼。

接下來我們會看到這么一個分支:

if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) { } else {}

首先我們不管heightMode,也就是父類的測量模式,剩下一個判定條件就是lp.height,也就是子類的高度。

既然有針對這個進行判定,那就是意味著肯定在此之前對child進行過measure,事實上,在這里我們一早就對這個地方進行過描述,這個方法正是measureChildBeforeLayout()。

還記得我們的measureChildBeforeLayout()執行的先行條件嗎

YA,just u see,正是不滿足(LinearLayout的測量模式非EXACTLY/child.height==0/child.weight/child.weight>0)之中的child.height==0

因為除非我們指定height=0,否則match_parent是等于-1,wrap_content是等于-2.

在執行measureChildBeforeLayout(),由于我們的child的height=match_parent,因此此時可用空間實質上是整個LinearLayout,執行了measureChildBeforeLayout()后,此時的mTotalLength是整個LinearLayout的大小

回到我們的例子,假設我們的LinearLayout高度為100,兩個child的高度都是match_parent,那么執行了measureChildBeforeLayout()后,我們兩個子控件的高度都將會是這樣:

child_1.height=100

child_2.height=100

mTotalLength=100+100=200

在一系列的for之后,執行到我們剩余空間:

int delta = heightSize - mTotalLength;

(delta=100[linearlayout的實際高度]-200=-100)

沒錯,你看到的的確是一個負數。

接下來就是套用weight的計算公式:

share=(int) (childExtra * delta / weightSum)

即:share=-100(2/10)=-20;*

然后走到我們所說的if/else里面

if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) {// child was measured once already above...// base new measurement on stored valuesint childHeight = child.getMeasuredHeight() + share;if (childHeight < 0) {childHeight = 0;}child.measure(childWidthMeasureSpec,MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));} 復制代碼

我們知道**child.getMeasuredHeight()=100**

接著這里有一條int childHeight = child.getMeasuredHeight() + share;

這意味著我們的**childHeight=100+(-20)=80;**

接下來就是走child.measure,并把childHeight傳進去,因此最終反饋到界面上,我們就會發現,在兩個match_parent的子控件中,weight的比是反轉的。

接下來沒什么分析的,剩下的就是走layout流程了,對于layout方面,要講的其實沒什么東西,畢竟基本都是模板化的寫法了。


4.小結

在這里,我們花費了大篇幅講解measureVertical()的流程,事實上對于LinearLayout來說,其最大的特性也正是兩個方向的排布以及weight的計算方式。

在這里我們不妨回過頭看一下,其實我們會發現在測量過程中,設計者總是有意分開含有weight和不含有weight的測量方式,同時利用height跟0比較來更加的細分每一種情況。

可能初看的時候覺得代碼太多,事實上一輪分析下來,方向還是很清晰的。畢竟有weight的地方前期都給個標志跳過,在測量完需要的數據(比如父控件的總高度什么的)后,再根據父控件的數據和weight再針對進行二次測量。

在文章的最后,我們小結一下對于測量這里的算法的不同情況下的區別以及原理:

  • 父控件是match_parent(或者精確值),子控件擁有weight,并且高度給定為0:

    • 子控件的高度比例將會跟我們分配的layout_weight一致,原因在于weight二次測量時走了else分支,傳入的是計算出來的share值
  • 父控件是match_parent(或者精確值),子控件擁有weight,但高度給定為match_parent(或者精確值):

    • 子控件高度比例將會跟我們分配的layout_weight相反,原因在于在此之前子控件測量過一次,同時子控件的測量高度為父控件的高度,在計算剩余空間的時候得出一個負值,加上自身的測量高度的時候反而更小
  • 父控件是wrap_content,子控件擁有weight:

    • 子控件的高度將會強行置為其wrap_content給的值并以wrap_content模式進行測量
  • 父控件是wrap_content,子控件沒有weight:

    • 子控件的高度跟其他的viewgroup一致

至此,LinearLayout針對measure的解析到此結束

感謝您的觀閱讀。

因為本人能力經驗有限,有些地方可能分析錯誤,如果您發現了,在下非常歡迎督促指正喲。

簡書:羽翼君

總結

以上是生活随笔為你收集整理的Android角落 不妨再看LinearLayout的全部內容,希望文章能夠幫你解決所遇到的問題。

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