關於Android UI組件LinearLayout屬性layout_weight與layout_width/height的問題

來源:互聯網
上載者:User

轉自:http://hi.baidu.com/wei_chou/item/04b51be1abb1e316595dd853

在網上搜尋了很多關於layout_weight的文章,眾說紛紜,且都不準確。後來自己動手測試,通過分析計算得出以下結論:

1、如果LinearLayout在其子組件相應排列方向上的大小值(layout_width/height)為wrap_content,則忽略所有子組件的layout_weight,且相應方向上的大小值也替換為wrap_content。例如:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_weight="0"    android:orientation="horizontal" >    <Button        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_weight="4"        android:text="Button01"/>    <Button        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_weight="3"        android:text="Button02"/>    <Button        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_weight="3"        android:text="Button03"/>    </LinearLayout>由於LinearLayout的android:orientation="horizontal",子組件水平排列,而android:layout_width="wrap_content",所有將忽略所有子組件的layout_weight,並將android:layout_width值替換為wrap_content。垂直方向同理。 2、layout_weight值表示該組件應該增加或減少的值占剩餘空間的比例,沒有優先順序之說。至於為什麼有的組件會不顯示,這不是因為優先順序的原因。通過以下公式的計算,你會明白。本人愚鈍,擬公式如下:                W = W1 + L * P;其中W表示最終寬度或高度,W1表示第一次測量的寬度/高度,L表示剩餘空間的值(可能為負數),P表示根據android:layout_weight屬性值計算出來的百分比。將上面代碼更改如下(注意android:orientation跟android:layout_width的對應關係),此時子組件的layout_width/height和layout_weight將被應用:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:layout_weight="0"    android:orientation="horizontal" >    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_weight="3"        android:text="Button01"/>    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_weight="2"        android:text="Button02"/>    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_weight="5"        android:text="Button03"/>    </LinearLayout>android對組件進行布局的時候會組件大小進行兩次計算:第一次是測量沒有應用android:layout_weight時的值,第二次是根據第一次測量值重新計算群組件應用android:layout_weight之後的實際值。設LinearLayout父組件寬度為w,由於三個Button的layout_width值都為wrap_content,為簡單起見,設第一次測量三個Button的寬度都為W1=w/5,合起來的總寬度為total_w = 3w/5。則剩餘空間的大小為L=w-total_w=2w/5,下面進行第二次計算,分別對三個Button的實際大小進行計算:Button01:                P = 3 / (3+2+5) = 0.3;                W1 = w/5 = 0.2w;

                W = W1 + L*P = w/5 + 2w/5 * 0.3 = 0.32w;                //增加了0.12w

Button02:

                P = 2 / (3+2+5) = 0.2;

                W1 = w/5 = 0.2w;

                W = W1 + L*P = w/5 + 2w/5 * 0.2 = 0.28w;                //增加了0.08w

Button03:

                P = 5 / (3+2+5) = 0.5;

                W1 = w/5 = 0.2w;

                W = W1 + L*P = w/5 + 2w/5 * 0.5 = 0.4w;                //增加了0.2w

結果顯而易見。那如果三個Button的layout_width值都為fill_parent會怎樣呢?此時W1=w;L=w-total_w=w-3*W1=-2w;Button01:                P = 3 / (3+2+5) = 0.3;                W1=w;

                W = W1 + L*P = w + (-2w) * 0.3 = 0.4w;                //減少了0.6w

Button02:

                P = 2 / (3+2+5) = 0.2;

                W1=w;

                W = W1 + L*P = w + (-2w) * 0.2 = 0.6w;                //減少了0.6w

Button03:

                P = 5 / (3+2+5) = 0.5;

                W1=w;

                W = W1 + L*P = w + (-2w) * 0.5 = 0;                //寬度為0,所以不顯示由於Button03的寬度為0,所以這時只能顯示Button01和Button02。而不是因為其layout_weight值比較大,優先順序低導致的。到這裡是不是突然覺得很簡單啊!如果Button03的layout_weight改為7呢?自己去算吧,W將小於0,因此也不會顯示。還有一種情況,如果設Button02的layout_width="wrap_content",其他都為fill_parent呢?計算方法一樣。垂直方向同理。另外當android:orientation="horizontal"時,垂直方向如何應用?首先適用本文第一條,否則當LinearLayout的android:layout_height="fill_parent"時,若子組件的android:layout_height="fill_parent",則縱向填滿,否則自適應大小。補充說明之妙用:
3、若不設定 LinearLayout 的 weightSum 以及所有子組件的 layout_weight 值,即兩者的值都為0,則將要出界的組件的尺寸將會被調整。規則如下:所有值為 
wrap_content 或 fill_parent 的組件,若按其正常尺寸,有部分在父組件邊界內而部分在父組件邊界外的,則將其尺寸調整到正好容納在邊界之內;完全在邊界外部的組件將會隱藏,即寬或高為0;所有值不為 wrap_content 或 fill_parent之外 的組件,即有固定尺寸的,如100dp,則無論在邊界內外都按固定尺寸顯示。問題:我不想給子組件設定固定的尺寸,也不想出界的組件會隱藏,而是想當我滾動內容的時候scrollTo(x, y) / scrollBy(x, y),出界的部分會顯示出來而不是依然隱藏。根據前面的第1、2條,我們知道應用weight可以讓組件出界,但卻會改變組件的大小。其實有簡單的辦法,見下一條。4、若 LinearLayout 的 weightSum 和子組件的 layout_weight 有一個不為0,當依次應用子組件的 layout_weight 來進行計算群組件尺寸的時候(見第2條),當某子組件與其前面的所有子組件的 layout_weight 值之和 正好等於 weightSum 的時候,則忽略其後所有子組件的 layout_weight 屬性,此時,其後的所有子組件將保持原始的尺寸。

根據本條特性,解決上面的問題很容易了,見代碼:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:orientation="horizontal">    <View        android:layout_width="0px"        android:layout_height="0px"        android:layout_weight="1" />    <Button        android:layout_width="wrap_content"        android:layout_height="400dp"        android:text="按  鈕0" />    <Button        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:text="按  鈕1" />    <Button        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:text="按  鈕2" /></LinearLayout>該布局中,由於View的android:layout_weight正好等於android:weightSum(這裡省略了,因為android:weightSum預設為所有子組件的android:layout_weight的值之和),所有的Button都會保持其原始的大小並出界。讀者可以自行測試其他情況,將android:weightSum和各子組件的android:layout_weight設定不同的值,看看效果。3、4條為後來補充。到這裡算是完善了。補充:更為簡單且規範的實現組件出界的方法:        
        重寫onMeasure()方法,調整參數,將測量模式設定為MeasureSpec.UNSPECIFIED
        @Override        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {                widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);                super.onMeasure(widthMeasureSpec, heightMeasureSpec);        }詳見我的另一篇文章,對測量(measure)的詳細解說。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.