你真的瞭解weight和weightSum嗎?

×

看到本文的標題,很多童鞋會一臉不屑的說,這有什麼不瞭解的。不就是通過weight來給子佈局按比例來分配空間嘛!好,這個答案也對也不對。 此時有人會疑惑了,爲什麼也對也不對? 我先來舉兩個最常見的例子:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="horizontal">

    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="A" />

    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="B" />

</LinearLayout>


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="horizontal">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="A" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="B" />

</LinearLayout>
Paste_Image.png

這兩個例子都能實現上圖的效果。那麼問題來了,這兩個方式有什麼區別嗎? 眼尖的童鞋立馬會說:當然有區別,一個 android:layout_width 是0, 另一個是 wrap_content。 那麼這兩個有什麼區別嗎? 爲什麼實現的效果是一樣的? 我還要問一句,真的是一樣嗎?

如果對這個問題有所疑惑,那麼兔子哥將帶領大家來深入瞭解一下weight和weightSum,並通過閱讀本篇文章,做到知其然,並且知其所以然。

什麼是weight和weightSum

某位偉人曾經說過,要對某個知識點深入瞭解,最好的切入點就是仔細閱讀知識點的定義。至於這位偉人是誰,什麼?想不起來了?不用想了,就是這篇博文的作者,兔子哥大人也! ~~~好了,扯了這麼多廢話!我們還是先步入正題,先看看Google是怎麼給 android:layout_weight 和 android:weightSum來定義的:

Layout Weight

LinearLayout also supports assigning a weight to individual children with the android:layout_weight
attribute. This attribute assigns an “importance” value to a view in terms of how much space it should occupy on the screen. A larger weight value allows it to expand to fill any remaining space in the parent view. Child views can specify a weight value, and then any remaining space in the view group is assigned to children in the proportion of their declared weight. Default weight is zero.

大體意思就是,android:layout_weight 這個屬性代表了一個“重要性”的值,這個值的大小代表了該控件能在屏幕中佔據多大的空間。這個值越大,表明該控件可以在父控件中佔據較多的“剩餘”空間。默認的weight是0。
在這裏,大家一定要注意“剩餘”兩個字!大家往往容易忽略這一點,導致出現了很多問題。舉個例子:水平方向佈局的父類有三個子類,父類總的寬度是100,子類的寬度分別是10,20,30。 那麼 android:layout_weight 這個屬性的目的,就是瓜分剩餘的 100 - 10 - 20 - 30,也就是剩餘的40的使用權。沒錯! 就是android:layout_weight 這個屬性 僅僅決定 哪個子類能瓜分到更多的40的部分!

android:weightSum

Defines the maximum weight sum. If unspecified, the sum is computed by adding the layout_weight of all of the children.

這個就很好理解了,weightSum定義了weight 總和的最大值。如果 android:weightSum 沒有定義,那麼默認值就是通過各個子類的 layout_weight 累加得到。

工作原理

講了這麼多,舉個例子來說明一下。


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="horizontal"
    android:weightSum="1">

    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="0.5"
        android:text="@string/hello_world" />

</LinearLayout>

效果如下圖:

Paste_Image.png

內部的計算原理是:
Button的寬度 = Button 的 width + Button的weight ***** 父佈局(LinearLayout)的寬度 / weightSum
上面的例子,也就是 Button的寬度 = 0 + 0.5 *** LinearLayout的寬度 / 1 = 0.5 * LinearLayout的寬度
也就是Button的寬度將佔屏幕的一半。

Google官方例子

結合上面的知識再看一下 Google的例子 ,可能體會的更加深刻。

首先看實現的效果:

Paste_Image.png

如果讓大家自己來實現這個效果的話,相信很多童鞋會採用相對佈局,將send按鈕位於屏幕最下方,然後上面的三個EditText從上往下依次排列。但是message的EditText要鋪滿剩餘的空間,這個怎麼實現? 有的童鞋會不屑的說了,這有什麼難的,把message的高度設置match_parent並且位於subject和send之間即可。代碼如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="16dp"
    android:paddingRight="16dp">

    <EditText
        android:id="@+id/et_to"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/to" />

    <EditText
        android:id="@+id/et_subject"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/et_to"
        android:hint="@string/subject" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/btn_send"
        android:layout_below="@id/et_subject"
        android:gravity="top"
        android:hint="@string/message" />

    <Button
        android:id="@+id/btn_send"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_gravity="right"
        android:text="@string/send" />
</RelativeLayout>


但是如果採用本文講解的weight可能會更加的簡單。這個佈局關鍵的一點是message要鋪滿subject與send之間的區域。問題是如何實現鋪滿呢? 對了! 本文講解的 weight 的核心就是瓜分父佈局剩餘的空間。全部瓜分不就是鋪滿嘛! 那麼代碼也就出來了:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:orientation="vertical" >
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/to" />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/subject" />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="top"
        android:hint="@string/message" />
    <Button
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:text="@string/send" />
</LinearLayout>

着重看一下message的佈局:


<EditText
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1"
       android:gravity="top"
       android:hint="@string/message" />

沒錯,採用了極爲巧妙的方法。其他的子佈局都不設置 layout_weight, 也就是默認是0 。 那麼message將獲取全部的剩餘空間,實現了鋪滿的效果。

後記

相信閱讀到這裏的童鞋們,對文章開頭的問題應該已經知道答案了。如果還有童鞋不知道答案,可以試着將文章開頭的兩個Button的內容改一下,一個叫AAAAAAAAA,一個叫B。您再看一下效果,可能就明白了。至於那個也對也不對的問題,“不對”的原因是他們要瓜分的是 剩餘 空間。本文止。

注意:當控件寬/高屬性設置爲match_parent時,剩餘空間爲負數,然後作爲負數的剩餘空間按比例分配相應控件。

參考:https://www.jianshu.com/p/9b0407252e8b

發佈了3 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章