布局属性layout_weight解析

关于Layout Weight,我们先来看一下官方释义。


LinearLayout通过子View的android:layout_weight属性,来为子View分配权重。layout_weight属性指定子View在屏幕上占有空间的重要性。较大的权重值使得子View可以扩充到填充父视图的任何剩余空间。子View可以指定一个weight值,然后LinearLayout根据子View声明的weight值所占的比例,来为它们分配剩余的空间。Layout Weight默认是0。

例如,如果有三个文本,其中两个声明权重为1,剩余一个没有声明权重,这个没有权重的文本,只会占据其内容所需的空间,并不会增加。而另外两个文本会同等的扩大,以填补三个文本在进行测量之后所剩余的空间。如果第三个文本声明的权重为2(而不是0),那么它的权重将比其它两个更重要,所以它会被分配一半的总剩余空间,前两个文本均分剩下的空间。

如果要创建一个线性布局,使其内部的每个子View使用屏幕上相等的空间,可以把每个子View的android:layout_height属性设置为“0dp”(对于垂直布局),或者把每个子View的android:layout_width属性设置为“0dp”(对于水平布局)。然后把每个子View的android:layout_weight属性设置为“1”。

文档读起来有点绕口,下面我们通过代码来进行验证。


(1).首先,来看看我们在开发中最常使用的方式。

布局文件:

<?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:orientation="horizontal">

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@android:color/holo_blue_bright"
        android:text="blog"/>

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:background="@android:color/holo_green_light"
        android:text="csdn"/>

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="3"
        android:background="@android:color/holo_orange_light"
        android:text="net"/>
</LinearLayout>

显示效果:


三个TextView在LinearLayout中水平排列,各个控件的layout_width都是0dp,第一个控件layout_weight为1,第二个控件layout_weight为2,第三个控件layout_weight为3。显示效果如我们预期,三个控件宽度比例为1:2:3。


(2).接下来,我们重新调整第1步中三个控件的layout_width和layout_weight。此时,各个控件的layout_width都是match_parent,控件从左到右layout_weight依次是1,2,2。

布局文件:

<?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:orientation="horizontal">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@android:color/holo_blue_bright"
        android:text="blog"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:background="@android:color/holo_green_light"
        android:text="csdn"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:background="@android:color/holo_orange_light"
        android:text="net"/>
</LinearLayout>

显示效果:


我们会发现,出现了跟我们预期截然不同的结果。那么为什么会出现这种情况呢,这时候我们再回到上面官方对weight的定义。 父视图根据子视图声明的weight值所占的比例,来为它们分配剩余的空间。也就是说,在这里LinearLayout先根据三个TextView的layout_width属性,为它们分配宽度,LinearLayout的宽度减去三个TextView的宽度,会有一个剩余宽度,然后LinearLayout将 剩余宽度按照三个TextView的layout_weight所占的比例来为它们分配。

这里,我们假设LinearLayout的宽度为totalWidth,每个TextView声明的宽度为childWidth(三个TextView都是match_parent,声明的宽度相等)。由于TextView的layout_width为match_parent,所以这里childWidth=totalWidth。
那么,可以计算出剩余宽度为totalWidth-childWidth*3 = -totalWidth*2。(注意:剩余空间可以为负值)

据此,我们可以计算出三个TextView的实际显示宽度。即TextView声明的宽度加上剩余宽度按weight比例分配的值。
第一个TextView的宽度:childWidth + (-totalWidth*2)*(1/5) = totalWidth*(3/5)
第二个TextView的宽度:childWidth + (-totalWidth*2)*(2/5) = totalWidth*(1/5)
第三个TextView的宽度:childWidth + (-totalWidth*2)*(2/5) = totalWidth*(1/5)
所以,这里出现了3:1:1的显示效果。


同理,我们也可以据此计算出上述第1步中1:2:3的结果。


(3).我们再来看另一种情况。将上述第2步中的三个控件的layout_width保持不变(即依旧是match_parent),layout_weight由依次是1,2,2,改为依次是1,2,3。

布局文件:

<?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:orientation="horizontal">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@android:color/holo_blue_bright"
        android:text="blog"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:background="@android:color/holo_green_light"
        android:text="csdn"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="3"
        android:background="@android:color/holo_orange_light"
        android:text="net"/>
</LinearLayout>

显示效果:


结果又一次出乎我们的意料,第三个控件竟然不见了。

依旧使用上述公式,计算一下我们就明朗了。
第一个TextView的宽度:childWidth + (-totalWidth*2)*(1/6) = totalWidth*(4/6)
第二个TextView的宽度:childWidth + (-totalWidth*2)*(2/6) = totalWidth*(2/6)
第三个TextView的宽度:childWidth + (-totalWidth*2)*(3/6) = totalWidth*(1/6)

虽然第三个TextView实际有父布局1/6的宽度,但是我们会发现第一个TextView和第二个TextView已经占满父控件宽度(4/6 + 2/6 = 1),所以第三个TextView被挤到屏幕之外了。


(4).还有一种情况也需要我们关注。现在LinearLayout中有两个TextView水平排列,两个TextView的layout_width都是wrap_content,layout_weight都是1,TextView均有文字内容,但文字长度不同。
直观告诉我们这两个控件一定会按照1:1的比例来显示,下面让我们看一下实际效果。

布局文件:

<?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:orientation="horizontal">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@android:color/holo_blue_bright"
        android:text="http://"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@android:color/holo_green_light"
        android:text="blog.csdn.net/ruancoder"/>
</LinearLayout>

显示效果:


实际结果否定了我们的猜测,两个TextView并未均分屏幕宽度。

但是无论我们如何修改width和weight,规则是不会改变的,即TextView的宽度等于TextView声明的宽度加上剩余宽度按weight比例分配的值。
这里,TextView的宽度声明为wrap_content,也就是其内部文字的宽度,两者文字的长度是不同的,所以相当于两者声明的宽度实际为其内部文字宽度。weight值相同,说明两者会平分剩余宽度。所以,就出现了我们所看到的现象,二者并未按照1:1的比例来显示,但二者的空白区域(即非文字显示区域)却是1:1的。

那么,如何达到1:1的显示效果呢,很简单,将两个TextView的layout_width都置为0dp即可。


(5).与layout_weight相关联的,还有一个weightSum属性。layout_weight是声明在子视图的,而weightSum是声明在父视图的。实际开发中,我们可能有这种需求,在一行中只有一个控件,但却需要该控件占据一半的屏幕宽度,此时可以使用layout_weight结合weightSum实现。

布局文件:

<?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:orientation="horizontal"
    android:weightSum="2">

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@android:color/holo_blue_bright"
        android:text="blog.csdn.net"/>
</LinearLayout>

显示效果:


通过weightSum属性,可以指定LinearLayout内部所有子视图的weight总和。如果该属性未设定,则其值为内部所有子视图的weight值相加计算的总和。

这里,父视图的weightSum等于2,子视图的layout_width等于0,且layout_weight等于1,所以子视图占据了父视图一半的宽度。


总结:
线性布局在为子控件分配尺寸时,首先按照子控件声明的尺寸进行分配,然后再加上剩余尺寸按weight所占比例计算的值。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值