6.2 布局管理

下面介绍Android界面布局中最常用的4种:帧布局、线性布局、相对布局和网格布局。

6.2.1 帧布局

FrameLayout帧布局,也可以叫做框架布局,是一种最简单的布局方式。在此布局下的所有视图和控件都将固定在屏幕的左上角显示,不能指定视图和控件的位置,但允许有多个视图和控件叠加,如图6-5所示。事实上,帧布局很少直接使用,而是使用它的子类,例如TextSwitcher、ImageSwitcher、DatePicker、TimePicker、ScrollView和TabHost。

图6-5 帧布局示意图

6.2.2 实例:使用帧布局

在本例中放置了2个ImageView和1个TextView,使用帧布局的效果如图6-6所示。

图6-6 帧布局实例

布局文件activity_main.xml代码如下:

        <?xml version="1.0" encoding="utf-8"?>
        <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"              ①
          android:layout_width="match_parent"                                                ②
          android:layout_height="match_parent">                                              ③

            <ImageView
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:src="@mipmap/background"/>                                             ④
            
            <ImageView
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:src="@mipmap/butterfly"/>

            <TextView
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@string/hello"                                                   ⑤
              android:textColor="@color/colorLabelText"                                      ⑥
              android:textSize="@dimen/label_textsize"/>                                     ⑦

        </FrameLayout>                                                                       ⑧

上述代码第①行~第⑧行是指定帧布局范围,帧布局和其他视图一样都有宽度和高度属性,在XML布局文件中的属性是android:layout_width和android:layout_height,见代码第②行和第③行,其他的视图代码也都有这两个属性,android:layout_width和android:layout_height取值可以采用:

❏ 具体数值。指定具体数值,这属于硬编码硬编码是指将可变变量用一个固定值来代替的方法。用这种方法编译后,如果以后需要更改此变量就非常困难了。——引自于百度百科http://baike.baidu.com/view/2024903.htm,例如200px,单位可以是px(像素)和dp/dip(设备独立像素)。

❏ fill_parent。填充、占满父容器。API级别8后被match_parent替代。

❏ match_parent。API级别8之后使用,替代fill_parent。

❏ wrap_content。刚好适合当前视图的大小。

布局文件activity_main.xml代码第④行的android:src属性是为ImageView提供显示图片,@mipmap/background是从资源目录res/mipmap中获取background.png图片,由于本例只有一套中密度图片,所以只在mipmap-mdpi目录中放置了图片。另一个ImageView控件的资源图片butterfly.png也是如此,如图6-7所示。

图6-7 放置资源图片

代码第⑤行android:text="@string/hello"是设置TextView显示的文字,TextView是标签控件,标签控件上显示的文字不是硬编码XML文件,而是通用@string/hello从引用res/values/strings.xml中的内容,strings. xml代码如下:

        <resources>
            <string name="app_name" Layout Sample /string>
            <string name="hello" HelloWorld /string>
        </resources>

代码第⑥行android:textColor="@color/colorLabelText"是设置TextView文字的颜色,颜色值是在res/values/colors.xml中声明的。

代码第⑦行android:textSize="@dimen/label_textsize"是设置TextView文字的字体,注意它的单位一般是sp,字体大小和控件尺寸等应该在res/values/dimens.xml中声明。

6.2.3 线性布局

线性布局是所有布局中最常用的,它可以让其中的视图垂直排列(如图6-8(a)所示)或水平排列(如图6-8(b)所示)。通常复杂的布局都是在线性布局中嵌套而成的。线性布局最重要的属性是:设置排列方向android:orientation属性,android:orientation="vertical"是垂直排列,android:orientation="horizontal"是水平排列。

图6-8 线性布局示意图

6.2.4 实例:使用线性布局实现登录界面

下面通过一个实例熟悉一下线性布局,这个实例是如图6-9所示的登录界面。它有两个TextView标签、两个EditText文本框,以及登录和注册按钮构成。这样的登录界面可以采用线性布局的垂直和水平嵌套实现。

图6-9 线性布局实例

布局文件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="match_parent"
               android:layout_height="wrap_content"
               android:gravity="center"
               android:text="@string/title"
               android:textSize="20sp"/>

           <LinearLayout                                                                    ②
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:orientation="horizontal">

               <TextView
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:text="@string/username"
                   android:textSize="15sp"/>

               <EditText
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"/>
           </LinearLayout>

           <LinearLayout                                                                    ③
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:orientation="horizontal">

           <TextView
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:text="@string/password"
                   android:textSize="15sp"/>

           <EditText
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:inputType="textPassword"/>    //设置输入类型为密码

           </LinearLayout>

           <LinearLayout                                                                    ④
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:orientation="horizontal">

               <Button
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:text="@string/login"
                   android:layout_weight="1"/>                                              ⑤
               <Button
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:text="@string/register"
                   android:layout_weight="1"/>                                              ⑥
           </LinearLayout>

        </LinearLayout>

从上述代码可见,登录界面采用了4个线性布局来实现,如图6-10所示,最外边是①号线性布局,它是垂直方向排列,从上到下有一个TextView和三个水平方向排列的线性布局。②排列号线性布局水平方向排列包含一个TextView(用户名:)和一个EditText。③号线性布局水平方向包含一个TextView(密码:)和一个EditText。④号线性布局水平方向排列包含登录和注册按钮。

图6-10 线性布局实例解释

上述布局文件activity_main.xml中代码第⑤行和第⑥行视图android:layout_weight属性是设置权重,就是该视图在父视图中所占用空间的比例,父视图LinearLayout中包含两个Button按钮(登录和注册),每个按钮各占用1/2,如图6-11(a)所示。如果登录按钮权重设置为2,注册按钮权重设置为1,修改代码如下:

图6-11 权重属性

        <Button                                    //登录按钮
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@string/login"
          android:layout_weight="2"/>
        <Button                                    //注册按钮
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@string/register"
          android:layout_weight="1"/>

那么登录按钮占用空间为3/4,注册按钮占用空间为1/4,如图6-11(b)所示。

6.2.5 相对布局

RelativeLayout相对布局,允许一个视图指定相对于其他视图或父视图的位置(通过视图id属性引用其他视图)。因此,可以以左右对齐、上下对齐、置于屏幕中央等形式来排列元素。相对布局在实际应用中比较常用。

相对布局如图6-12所示,先放置①号视图,然后②号视图与①号视图上对齐,③号视图与①号视图左对齐。而④号视图相对于父视图(所在的相对布局)居中对齐。

图6-12 相对布局示意图

6.2.6 实例:使用相对布局实现查询功能界面

下面通过一个实例熟悉一下相对布局,这个实例实现查询功能界面,如图6-13所示。

图6-13 相对布局实例

布局文件activity_main.xml代码如下:

        <?xml version="1.0" encoding="utf-8"?>
        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:padding="10dip">                                                    ①

          <TextView                                                                   ②
              android:id="@+id/label"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:text="@string/activity_main_search"/>

              <EditText                                                               ③
              android:id="@+id/entry"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"   
              android:layout_below="@id/label"                                        ④
              android:background="@android:drawable/editbox_background"/>             ⑤
 
          <Button                                                                     ⑥
              android:id="@+id/ok"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_alignParentRight="true"                                  ⑦
              android:layout_below="@id/entry"                                        ⑧
              android:layout_marginLeft="10dip"                                       ⑨
              android:text="@string/activity_main_confirm"/>

          <Button                                                                     ⑩
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_alignTop="@id/ok"                                        ⑪
              android:layout_toLeftOf="@id/ok"                                        ⑫
              android:text="@string/activity_main_cancel"/> 
        </RelativeLayout>

上述代码第②行声明一个id为label的TextView,其他的视图是相对于它摆放的,它相当于“地标”。

代码第③行声明一个id为entry的EditText,通过代码第④行的android:layout_below="@id/label"引用label, layout_below属性是声明entry在label之下。

代码第⑥行声明一个id为ok的Button,通过代码第⑧行的android:layout_below="@id/entry"引用entry, layout_below属性是声明ok在entry之下,代码第⑦行android:layout_alignParentRight="true"属性,使得ok按钮在父容器中靠右对齐。

代码第⑩行声明一个Button,他与ok按钮顶边对齐,见代码第⑪行android:layout_alignTop="@id/ok"。他被放置在ok按钮的左边,见代码第⑫行android:layout_toLeftOf="@id/ok"。

代码第⑤行是设置EditText的背景,注意它的取值是"@android:drawable/editbox_background"而非"@ drawable/editbox_ background",前缀android:表明editbox_background不是在当前工程中声明的,而是在Android框架中声明的。

图6-14 padding和margin概念

提示 padding和margin是在Android界面经常遇到的概念,这两个概念是从HTML和CSS借鉴过来的,margin是外边距,padding是内边距,如图6-14所示。padding和margin都有4个边,在Android中每一个都涉及5个属性,padding的5个属性是android padding、android:paddingLeft、android:paddingTop、android:paddingRight和android:paddingBottom,其中android:padding表示同时设置4个边距离。margin的5个属性是android:layout_margin、android:layout_marginLeft、android:layout_marginTop、android:layout_marginRight、android:layout_marginBottom,其中android:layout_margin表示同时设置4个边距离。

6.2.7 网格布局

GridLayout网格布局,是在Android 4及以后版本中推出的。网格布局不会显示行、列、单元格的边框线。图6-15是3行5列网格布局,使用属性android:rowCount ="3"和android:columnCount="5"设置网格行和列,android:orientation可以设置网格布局排列方向。而且网格布局可以设置行列合并,android:layout_columnSpan属性可以合并多列,android:layout_rowSpan属性可以合并多行。

图6-15 网格布局示意图

提示 网格布局是在Android 4及以后版本中推出的,要求Android SDK最低版本不低于14,否则不能使用网格布局,只能使用表格布局了。

6.2.8 实例1:使用网格布局实现计算器界面

计算器界面按钮很多,可以通过网格布局实现,图6-16是计算器界面。

图6-16 网格布局实例

布局文件activity_main.xml代码如下:

      <?xml version="1.0" encoding="utf-8"?>
      <GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="center_horizontal"
          android:columnCount="4"                  //设置列数
          android:orientation="horizontal"         //设置网格排列方向                   ①
          android:rowCount="5">                    //设置行数

          <Button
              android:id="@+id/one"
              android:text="1"/>
          …

          <Button
              android:id="@+id/six"
              android:text="6"/>

          <Button
              android:id="@+id/multiply"
              android:text="×"/>

          <Button
              android:id="@+id/seven"
              android:text="7"/>

          <Button
              android:id="@+id/eight"
              android:text="8"/>

          <Button
              android:id="@+id/nine"
              android:text="9"/>

          <Button
              android:id="@+id/minus"
              android:text="-"/>

          <Button
              android:id="@+id/zero"
              android:layout_columnSpan="2"                                          ②
              android:layout_gravity="fill"
              android:text="0"/>

          <Button
              android:id="@+id/point"
              android:text="."/>

          <Button
              android:id="@+id/plus"
              android:layout_gravity="fill"
              android:layout_rowSpan="2"                                             ③
              android:text="+"/>

          <Button
              android:id="@+id/equal"
              android:layout_columnSpan="3"                                          ④
              android:layout_gravity="fill"
              android:text="="/>
      </GridLayout>

代码第①行android:orientation="horizontal"属性是设置网格排列方向,horizontal是水平,vertical是垂直。代码第②行android:layout_columnSpan="2"是设置第4行的第1列与第2列合并。代码第③行android:layout_rowSpan="2"是设置第4列的第4行与第5行合并。代码第④行是android:layout_columnSpan="3"是设置第5行的第1、2、3列合并。

注意 设置合并单元格,一般需要设置android:layout_gravity="fill",这种设置可以将控件填充整个合并的单元格。

6.2.9 实例2:布局嵌套实现登录界面

各个布局之间可以嵌套,也可以使用include标签载入已定义好的的另一个布局文件。如图6-9所示的登录界面也可以采用include布局嵌套实现。

本例有4个布局文件,主布局文件只有一个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="match_parent"
              android:layout_height="wrap_content"
              android:gravity="center"
              android:text="@string/title"
              android:textSize="20sp"/>

          <include
              android:id="@+id/include01"                                            ①
              layout="@layout/layoutcase1"/>                                         ②

          <include
              android:id="@+id/include02"
              layout="@layout/layoutcase2"/>                                         ③

         <include
              android:id="@+id/include03"
              layout="@layout/layoutcase3"/>                                         ④

      </LinearLayout>

代码第①~④行是载入三个布局文件。代码第①行指定id属性,代码第②行是加载layoutcase1.xml文件。layoutcase1.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="wrap_content"
          android:orientation="horizontal">

          <TextView
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@string/username"
              android:textSize="15sp"/>

          <EditText
              android:layout_width="match_parent"
              android:layout_height="wrap_content"/>
      </LinearLayout>

layoutcase2.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="wrap_content"
        android:orientation="horizontal">

        <TextView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@string/password"
          android:textSize="15sp"/>

        <EditText
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:inputType="textPassword"/>

    </LinearLayout>

layoutcase3.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="wrap_content"
        android:orientation="horizontal">

        <Button
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_weight="1"
          android:text="@string/login"/>

        <Button
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_weight="1"
          android:text="@string/register"/>
    </LinearLayout>

这些布局文件比较简单,这里就不再赘述了。