LinearLayout 中不得不说的几个重要属性

3,720 阅读6分钟

关于LinearLayout

LinearLayout 在布局使用中比较频繁,一般可以设置成horizontal(横向)、vertical(竖向)两个方向,不过LinearLayout还有如下几个重要的属性,了解这几个属性可以让我们更加全面地认识linearLayout的真正功能。

1、weight 属性

weight属性意思是占比,就是占用的空间的大小,其实它的真正意义是剩余空间的占比。比如我们添加两个TextView,其中的text1添加android:layout_weight="1",text2添加android:layout_weight="2",如下设置:

< 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:gravity="center"
        android:layout_weight="1"
        android:background="#FF0000"
        android:text="text1" />
    < TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_weight="2"
        android:background="#00FF00"
        android:text="text2" />
< /LinearLayout>


结果会发现text2的宽度差不多是text1的两倍。假设每个text的宽度是120px , 那么在1080P的屏幕上,刚开始剩余空间是840px,text1的weight占1,text2的weight占2,所以text1的宽度是 120 + 840 / 3 = 400px,text2的宽度是 120 + 840 * 2 / 3 = 680px ,text2的宽度确实比text1大,这与程序运行结果一样。

那么通过上面的示例,你是不是觉得weight越大占用的空间就越大呢? 当然不是。如果我们把text1和text2都设置成match_parent 那会怎样呢 :

< 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:gravity="center"
        android:layout_weight="1"
        android:background="#FF0000"
        android:text="text1" />
    < TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_weight="2"
        android:background="#00FF00"
        android:text="text2" />
< /LinearLayout>


结果显示text1的宽度比text2的还大,但是明明text1 的weight比text2的weight小阿,其实这和上面的计算方式一样的,一开始text1和text2都是match_parent,所以各占用1080px,那剩余空间是1080 - 10802 = -1080px ,是个负数。text1的weight是1,所以text1的宽度是 1080 + (-1080)/3 = 720px ,而text2的是weight是2,所以text2的宽度是 1080 + (-1080) 2 / 3 = 360px ,所以text1的宽度比text2的还大。

其实用LinearLayout+ weight可以代替一些RelativeLayout才能做的功能,比如我们要做一个自适应的布局,左右两个按钮,可以根据屏幕的大小适应,左按钮始终最左边,右按钮始终在最右边,像下面这样:


这是很常见的需求,这个小布局有多种实现方式 :
第一种,最简单就是用RelativeLayout,设置layout_alignParentLeft="true"layout_alignParentRight="true"就可以了。
第二种,也可以用FrameLayout,通过设置layout_gravity属性来实现,比如 :

< FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    < Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:background="#FF0000"
        android:layout_gravity="left"
        android:text="左" />
    < Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:background="#00FF00"
        android:layout_gravity="right"
        android:text="右" />
< /FrameLayout>

上面代码也可以实现让两个控件位居左右并自适应屏幕。那么我们的LinearLayout是否也可以这样呢,在LinearLayout中设置layout_gravity是无效的,因为LinearLayout是线性的布局,必须从左到右或从上到下的顺序,要想位居左右必须有控件占满中间的部分,所以第三种方法就是利用LinearLayout + Space来实现 :

< LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    < Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:background="#FF0000"
        android:text="左" />
    < Space
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        />
    < Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:background="#00FF00"
        android:text="右" />
< /LinearLayout>

这代码巧妙的地方是利用Space设置weight为1来占满剩余空间,从而实现效果。

2、weightSum 属性

weightSum属性与weight属性有很大关系,通过weightSum控制weight的最大占比。比如我们这样设置 :

< LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:weightSum="3"
    android:orientation="horizontal">
    < TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_weight="1"
        android:background="#FF0000"
        android:text="text1" />
   
    < TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_weight="1"
        android:background="#00FF00"
        android:text="text2" />
< /LinearLayout>


text1与text2本来是一样的weight,可是结果它们都没有撑满屏幕。因为weightSum="3",也就是说text1、text2占用的宽度是 120 + 840 / 3 = 400px ,右边还有剩余280px。如果text1与text2的weight超过了weightSum会怎样,我们设置如下看看效果 :

< LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:weightSum="3"
    android:orientation="horizontal">
    < TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_weight="2"
        android:background="#FF0000"
        android:text="text1" />
    < TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_weight="2"
        android:background="#00FF00"
        android:text="text2" />
< /LinearLayout>


结果发现text2的文字快到屏幕外了,说明text2的宽度超出了屏幕。其实计算方式还是一样的,它们各占剩余空间的 2/3。我们上面说过text1与text2的宽度都是120px,剩余840,那么此时text1的宽度为 120 + 840 * 2 / 3 = 680px ,两个都是 680px,那text2当然被挤到屏幕外去了。
weightSum属性可以用来控制weight属性占用剩余空间的比例。比如我们要做一个布局,一个按钮居中,它宽度是屏幕的一半,还要自适应屏幕,效果如下:

你怎么做? 难道我们要在代码上通过获取屏幕宽度动态设置按钮的宽度吗?还是在xml布局上写死宽度,但是这样要在每个分辨率都适配一个宽度值 … No,No,No,这些方法都很low逼。我们可以利用weightSum属性,代码如下:

< LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="horizontal"
    android:weightSum="2">
    < Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="按钮" />
< /LinearLayout>

运行代码看到按钮半宽居中,自适应所有分辨率的屏幕,符合要求。注意LinearLayout中设置的android:gravity="center",它让子View居中放置。

3、divider 、showDividers 属性

以往我在设置分割线时,都是新增一个View,用来显示分割线,直到我发现在LinearLayout中添加分割线的新方法。LinearLayout显示分割线主要涉及divider 、showDividers 属性 : android:divider用于设置分割线的样式,可以是xml的drawable也可以是图片。android:showDividers = "middle|end|beginning|none" 其每个选项的作用:

  • middle 在每一项中间添加分割线
  • end 在整体的最后一项添加分割线
  • beginning 在整体的最上方添加分割线
  • none 不显示分割线

我们先创建一个custom.xml的drawable ,注意设置了宽高,不然是显示不出来的:

< ?xml version="1.0" encoding="utf-8"?>
< shape xmlns:android="http://schemas.android.com/apk/res/android">
    < solid android:color="@android:color/holo_red_light" />
    < size android:height="12dp" android:width="2dp"/>
< /shape>

设置成android:showDividers = “beginning”时:

设置成android:showDividers = “end”时:

设置成android:showDividers = “middle”时:

还可以组合设置 ,android:showDividers=”beginning|end|middle” ,显示结果:

最后如果大家发现了什么的重要的属性或巧妙的用法,也可以一起交流哈。

参考