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取值可以采用:
❏ 具体数值。指定具体数值,这属于硬编码,例如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>
这些布局文件比较简单,这里就不再赘述了。