LinearLayout中layout_weight的理解

  • Post author:
  • Post category:其他


LinearLayout是Android开发中经常用到的布局容器,它的使用方法比较简单,通常用于简单的需要顺序排列View的场景。当然今天文章的主角不是LinearLayout,而是讲View的一个与LinearLayout密切相关的属性:layout_weight,它表示LinearLayout的额外空间怎么分配给子View。然而,它使用起来并没有听上去那么简单。由于垂直布局和水平布局原理一样,下面的讨论全部是基于水平布局的。

首先来看一个例子。

<LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal" >
        <TextView
            android:background="#ff0000"
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:text="111111"
            android:textColor="@android:color/white"
            android:gravity="center"
            android:layout_weight="1"/>
        <TextView
            android:background="#00ff00"
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:text="2222"
            android:textColor="@android:color/white"
            android:gravity="center"
            android:layout_weight="2" />
        <TextView
            android:background="#0000ff"
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:text="3333333333"
            android:textColor="@android:color/white"
            android:gravity="center"
            android:layout_weight="3" />
    </LinearLayout>


程序中分别设置layout_weight为1,2,3,按照我们对layout_weight的理解,三个TextView宽度的比值应该为1:2:3,那么实际结果怎样呢?结果的确像我们预料的一样。这里需要注意的是,我们把TextView的layout_width都设置为0dp,这里为什么一定要这样来设置呢,我们后面再来说这个问题。

我们对程序稍微做一点修改,将其中三个TextView的layout_width改为wrap_content,再来看看效果。

结果有点出乎我们的意料,并没有出现之前1:2:3的形式,这是什么原因呢?

问题还是出在layout_weight这个属性,它表示LinearLayout中的额外空间是怎么来划分的,需要注意额外二字,也就是说,layout_weight所规定的比值并不是对所有LinearLayout空间的划分,而是要减去View已经占据的空间,剩余的空间再按照比例分配给各个View。放在这个例子中,就是先减去三个TextView的wrap_content的宽度,然后将剩余的空间按照1:2:3的比例分配给三个TextView。回头看第一个例子,由于三个TextView的宽度都为0,所谓的额外空间,其实就是LinearLayout的全部空间。

根据以上结论,我们可以得到一个公式,用来计算LinearLayout中子View的实际宽度。假设每个View宽度固定为W,LinearLayout的宽度为L,三个子View的layout_weight分别为1:2:3,那么我们可以分别的到三个View的宽度的计算公式

WidthView1 = L  +(L – 3W)/6

WidthView2 = L  +(L – 3W)*2/6

WidthView3 = L  +(L – 3W)*3/6

分析一下上面的公式,(L – 3W)是当前剩余的(额外)空间(这个空间可以为负值,这种情况下会产生很多奇怪的现象,后面我们会看到),将额外的空间分成6份,View1占其中的一份,就得到了 (L – 3W)/6,View1的宽度等于自身的宽度加上额外得到的宽度,就得到了上面这个公式,其他两个View以此类推。

我们已经知道layout_weight对空间分配的原理,下面通过更多的例子来加深理解。看代码:

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal" >
        <TextView
            android:background="#ff0000"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:text="111111"
            android:textColor="@android:color/white"
            android:gravity="center"
            android:layout_weight="1"/>
        <TextView
            android:background="#00ff00"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:text="2222"
            android:textColor="@android:color/white"
            android:gravity="center"
            android:layout_weight="2" />
        <TextView
            android:background="#0000ff"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:text="33333333"
            android:textColor="@android:color/white"
            android:gravity="center"
            android:layout_weight="3" />
    </LinearLayout>

在不看结果的情况下,我们先来分析一下。每个子View的宽度为match_parent,假设LinearLayout的宽度为L,那么额外空间就是(L – 3L),即 -2L,我们之前提到过这个值可以为负值。然后继续套用公式,三个View分配到的额外空间分别为 -2L/6、-2*2L/6、-3*2L/6,加上各自View本身的空间,得到最终结果分别是2L/3、L/3、0。好吧,我们发现第三个View的宽度竟然是0,那么运行结果真的是这样吗?

结果和我们预期的一样,这也验证了之前分析的正确性。

如果之前例子中的三个View中的View有的没有layout_weight属性,结果是什么样子呢?

<LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal">

        <TextView
            android:layout_width="5dp"
            android:layout_height="60dp"
            android:background="#ff0000"
            android:gravity="center"
            android:text="1"
            android:textColor="@android:color/white" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:layout_weight="1"
            android:background="#00ff00"
            android:gravity="center"
            android:text="2"
            android:textColor="@android:color/white" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:layout_weight="1"
            android:background="#0000ff"
            android:gravity="center"
            android:text="3"
            android:textColor="@android:color/white" />
    </LinearLayout>

上面的程序中,View1的width为5dp,View2和View3为0dp,但是只有View2和View3设置了layout_weight属性,为1:1。所以,结果应该是这样:View1的宽度为5dp,剩余的空间被View2和View3平分,看结果。

layout_weight的问题我相信已经讲清楚了,再来看另外一个诡异的问题。

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal">

        <TextView
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:layout_weight="1"
            android:background="#ff0000"
            android:gravity="center"
            android:text="11111111111111"
            android:textColor="@android:color/white" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:layout_weight="2"
            android:background="#00ff00"
            android:gravity="center"
            android:text="2"
            android:textColor="@android:color/white" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:layout_weight="3"
            android:background="#0000ff"
            android:gravity="center"
            android:text="3"
            android:textColor="@android:color/white" />
    </LinearLayout>

看起来和我们的第一个例子没什么差别,但是,结果却有点出乎意料,View错位了。


这是什么原因呢,都是LinearLayout的BaselineAligned属性惹的祸。BaselineAligned会使得它的子View的文本基准线对齐。看下图中的红线位置,文字都是水平对齐的,文字对齐导致了View在垂直方向上的位置发生了变化。







如果要解决这个问题,只需要在LinearLayout中设置一个属性android:baselineAligned=”false”,设置之后的效果如图







上面主要对LinearLayout中经常用到的layout_weight属性进行了分析,并且对

android:baselineAligned属性做了说明,相信

很多同学都遇到过上面提到的问题。我也曾在使用中产生过疑惑和不解,希望上面的内容能够帮助到有需要的同学。

欢迎关注我的公众号一起交流学习



版权声明:本文为goodlixueyong原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。