Android开发入门百战经典 (程序员典藏)
上QQ阅读APP看书,第一时间看更新

3.4 Android线性布局的重要属性

3.3节的实例中用到了两个属性gravity和layout_weight,这两个属性在Android开发中会经常用到,用法也比较复杂,下面讲解这两个属性的用法。

3.4.1 gravity属性

Android中的gravity属性有两种形式:layout_gravity和gravity,这两种有什么区别呢?从字面意思上就可以大概理解,第一个layout_gravity控制控件在父布局中的位置(和margin比较类似), gravity可以控制控件中内容的显示位置(和padding比较类似)。下面还会通过实例来比较这两个属性的效果。除了上面用到的属性值center之外,还提供了如表3.3所示中常用属性值供开发者调用(一次设置多个属性值用 “|”隔开):

表3.3 gravity属性

首先我们看一下layout_gravity的用法(activity_main.xml):

        <? 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="vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:text="center_horizontal"
                android:textSize="30dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="right"
                android:text="right"
                android:textSize="30dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="left"
                android:text="left"
                android:textSize="30dp" />

        </LinearLayout>

上述代码设置了Linearlayout的orientation属性值为vertical(垂直布局),添加了三个TextView控件,并分别为这三个TextView添加了layout_gravity属性,其值分别为center_horizontal(水平居中)、right(居右)和left(居左),这时看一下预览窗口中的显示如图3.18所示。

图3.18 layout_gravity属性示意图一

下面修改orientation属性值为horizontal,然后看一下另外几个属性值的用法,修改activity_main.xml如下:

        <? 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_gravity="center_vertical"
                android:text="center_vertical"
                android:textSize="30dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                android:text="bottom"
                android:textSize="30dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="top"
                android:text="top"
                android:textSize="30dp" />

        </LinearLayout>

这里同样添加了三个TextView并分别设置了其layout_gravity属性值为center_vertical(垂直居中)、bottom(底部)和top(顶部),这时查看效果如图3.19所示。

图3.19 layout_gravity属性示意图二

可以看出,这时center_vertical将垂直居中,top将位于界面的顶部,bottom将位于界面的底部。

下面来看gravity属性的用法,代码如下:

        <? 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="vertical">

            <TextView
                android:layout_width="150dp"
                android:layout_height="150dp"
                android:layout_gravity="center_horizontal"
                android:background="#41e67b"
                android:gravity="center_horizontal|center_vertical"
                android:text="center"
                android:textSize="30dp" />

            <TextView
                android:layout_width="120dp"
                android:layout_height="120dp"
                android:layout_gravity="left"
                android:background="#355fa1"
                android:gravity="right|bottom"
                android:text="right|bottom"
                android:textSize="30dp" />

            <TextView
                android:layout_width="150dp"
                android:layout_height="150dp"
                android:layout_gravity="right"
                android:background="#afb639"
                android:gravity="top|right"
                android:text="top|right"
                android:textSize="30dp" />

        </LinearLayout>

为了演示方便,将各个TextView的宽和高都设置得足够大并为每个TextView都添加了background属性。第一个TextView添加了两个gravity属性值,中间用 “|”符号隔开,这两个属性值(center_horizontal和center_vertical)和一个center是一样的效果;第二个TextView为gravity添加了两个属性值right|bottom即右下角;第三个TextView设置gravity属性值为top|right即右上角。查看右侧的预览窗口,如图3.20所示。

图3.20 gravity属性示意图

3.4.2 layout_weight属性

layout_weight在分配屏幕的宽高上有很大的用处,它的用法很灵活,结合不同的宽高值和weight值可以实现不同的效果和要求。

1. layout_width="match_parent"

首先看一下设置宽为match_parent时,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:orientation="horizontal">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="5"
                android:background="#cc5858"
                android:text="layout_weight=5"
                android:textSize="20dp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="#5baf54"
                android:gravity="center_horizontal"
                android:paddingBottom="15dp"
                android:text="layout_weight=1"
                android:textSize="20dp" />
        </LinearLayout>

上述代码中LinearLayout的orientation设置成了horizontal水平布局,在LinearLayout中添加了两个TextView并设置其宽的属性为match_parent(若此时不添加layout_weight属性,则第一个TextView将会覆盖第二个TextView)。为第一个TextView设置了layout_weight属性值为5,为第二个TextView设置了layout_weight属性值为1,这两个值具体有什么作用可以查看预览窗口,如图3.21所示。

图3.21 layout_weight属性示意图一

为了演示方便,这里为TextView添加了background属性,可以看出layout_weight为5时反而宽度很小,layout_weight为1时宽度很大,两个TextView的比例基本上是1:5。

修改第一个TextView的layout_weight值为10,再次查看如图3.22所示。第一个TextView的宽被压缩得更小了,当第一个TextView的layout_weight为100时,如图3.23所示。

图3.22 layout_weight属性示意图二

图3.23 layout_weight属性示意图三

可以看出第一个TextView基本被压缩地隐藏了。

2. layout_width="wrap_content"

修改TextView的宽为wrap_content时再次看一下效果,修改代码如下:

        <? 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="5"
                android:background="#cc5858"
                android:text="layout_weight=5"
                android:textSize="20dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="#5baf54"
                android:gravity="center_horizontal"
                android:paddingBottom="15dp"
                android:text="layout_weight=1"
                android:textSize="20dp" />
        </LinearLayout>

再次查看预览窗口,如图3.24所示。可以看出,和设置match_parent相反,设置为wrap_content时,layout_weight的值越大占据的宽越大,但是并没有按照5:1显示。再次修改第一个TextView的layout_weight属性值为10,预览图片如图3.25所示。第一个TextView的宽仅仅增加了一点,第二个TextView仍然是一行包裹显示。也就是说不管第一个TextView的layout_weight值有多大,第二个TextView都会包裹内容,不会被压缩到消失。

图3.24 layout_weight属性示意图四

图3.25 layout_weight属性示意图五

3. layout_width="0dp"

设置layout_width为0dp时才是正确的layout_weight属性使用方法,因为SDK中对layout_weight的使用方法有如下解释:

        In order to improve the layout efficiency when you specify the weight,
    you should change the width of the EditText to be zero (0dp). Setting the
    width to zero improves layout performance because using "wrap_content"as
    the width requires the system to calculate a width that is ultimately
    irrelevant because the weight value requires another width calculation to
    fill the remaining space.

也就是说,在某个方向上使用layout_weight属性,推荐将这个方向上的width设置成0dp,系统将会采用另一种算法来计算控件的控件占比,这时layout_weight属性值和占据的“宽度”将成正比例。

修改activity_layout.xml代码如下:

        <? 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="2"
                android:background="#cc5858"
                android:padding="10dp"
                android:text="layout_weight=2"
                android:textSize="20dp" />

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="#5baf54"
                android:gravity="center_horizontal"
                android:padding="10dp"
                android:text="layout_weight=1"
                android:textSize="20dp" />
        </LinearLayout>

因为布局是水平布局,所以其方向上的width就是layout_width,设置layout_width为0dp,查看预览窗口如图3.26所示。

图3.26 layout_weight属性示意图六

可以看出,layout_weight为2的TextView所占据的宽度是layout_weight为1的TextView所占据宽度的两倍,因此,推荐在开发时使用0dp。

3.4.3 weightSum属性

上面讲解了layout_weight属性的使用,Android还提供了一个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:gravity="center"
            android:orientation="horizontal"
            android:weightSum="2">

            <TextView
                android:layout_width="0dp"
                android:textSize="28dp"
                android:gravity="center"
                android:textColor="#ffffff"
                android:background="#1d6e09"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Hello World! " />
        </LinearLayout>

上述代码中weightSum放在父布局中并设置其值为2,这时可以认为整个宽为2,在子控件TextView中设置layout_weight为1并设置其layout_width为0dp,可以认为TextView占据了整个宽的一半,如图3.27所示。

图3.27 weightSum属性示意图一

可以看出,TextView居中并占据整个宽的一半。两个控件时同样也可以按照比例占据屏幕宽的一半,修改代码如下:

        <? 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="6">

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="2"
                android:background="#759c6c"
                android:gravity="center"
                android:text="2"
                android:textColor="#ffffff"
                android:textSize="28dp" />

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="#b33174"
                android:gravity="center"
                android:text="1"
                android:textColor="#ffffff"
                android:textSize="28dp" />
        </LinearLayout>

上述代码设置父布局的weightSum为6,将整个屏幕的宽分成6份,将第一个TextView的layout_weight属性值设为2,它将占据2份屏幕的宽,将第二个TextView的layout_weight属性值设为1,它将占据1份屏幕的宽,查看预览窗口如图3.28所示。

图3.28 weightSum属性示意图二

可以看出,第一个TextView是第二个TextView的宽的两倍,这两个TextView占据整个屏幕的一半。