看到本文的标题,很多童鞋会一脸不屑的说,这有什么不了解的。不就是通过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>
这两个例子都能实现上图的效果。那么问题来了,这两个方式有什么区别吗? 眼尖的童鞋立马会说:当然有区别,一个 android:layout_width 是0, 另一个是 wrap_content。 那么这两个有什么区别吗? 为什么实现的效果是一样的? 我还要问一句,真的是一样吗?
如果对这个问题有所疑惑,那么兔子哥将带领大家来深入了解一下weight和weightSum,并通过阅读本篇文章,做到知其然,并且知其所以然。
什么是weight和weightSum
某位伟人曾经说过,要对某个知识点深入了解,最好的切入点就是仔细阅读知识点的定义。至于这位伟人是谁,什么?想不起来了?不用想了,就是这篇博文的作者,兔子哥大人也! ~~~好了,扯了这么多废话!我们还是先步入正题,先看看Google是怎么给 android:layout_weight 和 android:weightSum来定义的:
Layout Weight
to individual children with the android:layout_weight
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>
效果如下图:
内部的计算原理是:
Button的宽度 = Button 的 width + Button的weight * 父布局(LinearLayout)的宽度 / weightSum
上面的例子,也就是 Button的宽度 = 0 + 0.5 * LinearLayout的宽度 / 1 = 0.5 * LinearLayout的宽度
也就是Button的宽度将占屏幕的一半。
Google官方例子
结合上面的知识再看一下 Google的例子 ,可能体会的更加深刻。
首先看实现的效果:
如果让大家自己来实现这个效果的话,相信很多童鞋会采用相对布局,将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。您再看一下效果,可能就明白了。至于那个也对也不对的问题,“不对”的原因是他们要瓜分的是 剩余 空间。本文止。