布局管理器
在设计安卓的应用界面时,每个控件都需要设置具体位置和大小,通常要使用 Android 的布局管理器来设置。Android 提供了以下 5 种布局管理器:
布局管理器 | 功能 |
---|---|
线性布局管理器 | 在垂直或水平方向上按顺序设置组件的位置 |
相对布局管理器 | 通过组件之间相互定位来确定组件的位置 |
帧布局管理器 | 没有定位方式,默认情况下所有组件摆放在左上角,逐个覆盖 |
表格布局管理器 | 将组件按照表格的行和列来放置 |
网格布局管理器 | 通过网格并可以跨行和跨列放置组件 |
还有一种绝对布局管理器,使用二维空间坐标来设置组件的位置,但是它在 Android 2.0 之后被废弃。
线性布局管理器
线性布局管理器 LinearLayout将包含的组件按照垂直方向或者水平方向,按照顺序依次排列,可以是垂直方向也可以是水平方向。
xml 属性
LinearLayout 的一些重要的 xml 属性如下。
xml 属性 | 说明 |
---|---|
android:id | 为当前布局管理器指定一个 ID,在 R.java 文件中会自动派生一个对应的属性 |
android:layout_width | 设置该组件的基本宽度,可选 fill_parent、match_parent 和 wrap_content |
android:layout_height | 设置该组件的基本高度,可选 fill_parent、match_parent 和 wrap_content |
android:orientation | 设置布局管理器内组件的排列方式,horizontal 水平排列,vertical 垂直排列 |
android:gravity | 设置布局管理器内组件的显示位置 |
android:background | 为该组件设置背景,可以是背景图片,也可以是背景颜色 |
其中 fill_parent 和 match_parent 表示与父容器的宽度相同,wrap_content 组件恰好能包裹它的内容,android:gravity 其可选值包括 top、bottom、left、right、center_vertical、fill_vertical、center_horizontal、fill_horizontal、center、fill、clip_vertical 和 clip_horizontal。
LinearLayout 的子控件还常用到以下 xml 属性。
xml 属性 | 说明 |
---|---|
android:gravity | 设置组件在父容器中的位置,其可选值包括 top、bottom、left、right、center_vertical、fill_vertical、center_horizontal、fill_horizontal、center、fill、clip_vertical 和 clip_horizontal |
android:layout_weight | 设置组件所占的权重的,即设置组件占父容器剩余空间的比例。该属性的默认值为 0 表示需要显示多大的视图就占据多大的屏幕空间,当设置一个高于零的值时则将父容器的剩余空间分割 |
样例
基于 LinerLayout 设计一款计算器 App 的界面,思路还是很直接的,只需要将各个按钮按顺序排列即可。主要难点在于最后 2 行分别有 2 个按钮跨了 2 行或 2 列。由于不是使用 GridLayout 布局,因此不能简单地进行排列,而是应该先放置一个 LinerLayout,然后里面再嵌套 2 个 LinerLayout 分别设置 2 排按钮,最后再用剩余空间填充等号按钮。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF">
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/msg"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="mc"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="m+"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="m-"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="mr"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="C"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="+/-"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="/"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="*"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="7"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="8"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="9"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="-"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="4"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="5"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="6"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="+"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="3">
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="1"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="2"
android:layout_weight="1" />
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="3"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button android:layout_width="0px"
android:layout_height="wrap_content"
android:text="0"
android:layout_weight="2" />
<Button android:layout_width="0px"
android:layout_height="wrap_content"
android:text="."
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
<LinearLayout android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1">
<Button android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="="
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
相对布局管理器
相对布局管理器 RelativeLayout 是通过组件之间的相对位置,来确定每个组件在界面中如何显示。
xml 属性
RelativeLayout 支持的常用 xml 属性如下所示。
xml 属性 | 说明 |
---|---|
android:gravity | 设置布局管理器中各子组件的对齐方式 |
android:ignoreGravity | 指定哪个组件不受 gravity 属性的影响 |
想要设置组件的相对位置,只有上面介绍的这两个属性是不够的,RelativeLayout 提供了一个内部类 RelativeLayout.LayoutParams。通过 LayoutParams 提供的大量 xml 属性,可以很好地控制相对布局管理器中各组件的分布方式。
xml 属性 | 说明 |
---|---|
android:layout_above | 其他 UI 组件的 ID 属性,指定该组件位于哪个组件的上方 |
android:layout_alignBottom | 其他 UI 组件的 ID 属性,指定该组件与哪个组件的下边界对齐 |
android:layout_alignLeft | 其他 UI 组件的 ID 属性,指定该组件与哪个组件的左边界对齐 |
android:layout_alignParentBottom | 其他 UI 组件的 ID 属性,指定该组件是否与布局管理器底端对齐 |
android:layout_alignParentLeft | boolean 值,指定该组件是否与布局管理器左边对齐 |
android:layout_alignParentRight | boolean 值,指定该组件是否与布局管理器右边对齐 |
android:layout_alignParentTop | boolean 值,指定该组件是否与布局管理器顶端对齐 |
android:layout_alignRight | boolean 值,指定该组件与哪个组件的右边界对齐 |
android:layout_alignTop | boolean 值,指定该组件与哪个组件的上边界对齐 |
android:layout_below | boolean 值,指定该组件位于哪个组件的下方 |
android:layout_centerHorizontal | boolean 值,指定该组件是否位于布局管理器水平居中的位置 |
android:layout_centerInParent | boolean 值,指定该组件是否位于布局管理器的中央位置 |
android:layout_center Vertical | boolean 值,指定该组件是否位于布局管理器垂直居中的位置 |
android:layout_toLeftOf | boolean 值,指定该组件位于哪个组件的左侧 |
android:layout_toRightOf | boolean 值,指定该组件位于哪个组件的右侧 |
样例
要用 RelativeLayout 实现梅花布局,可以在页面中间填充一个空白的 TextView 作为基准,设置 4 个按钮分别相对 TextView 在上下左右四个方位即可。注意需要先进行对齐,也就是 x 轴和 y 轴都要确定方位,否则控件会出现在奇怪的位置。
<?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="match_parent">
<TextView
android:id="@+id/btn_center"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:layout_centerVertical="true" />
<Button
android:id="@+id/btn_top"
style="@style/ButtonStyle2"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_above="@+id/btn_center"
android:layout_centerHorizontal="true"
android:text="上边" />
<Button
android:id="@+id/btn_bottom"
style="@style/ButtonStyle2"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_below="@+id/btn_center"
android:layout_centerHorizontal="true"
android:text="下边" />
<Button
android:id="@+id/btn_left"
style="@style/ButtonStyle2"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/btn_center"
android:text="左边" />
<Button
android:id="@+id/btn_right"
style="@style/ButtonStyle2"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/btn_center"
android:text="右边" />
</RelativeLayout>
帧布局管理器
帧布局管理器 FrameLayout中,每加入一个组件都会创建一个空白的区域,这个区域被称为帧。默认情况下这些帧会被放置在屏幕的左上角,多个组件层叠排序,后面的组件覆盖前面的组件。
xml 属性
FrameLayout 支持的常用 xml 属性如下所示。
xml 属性 | 说明 |
---|---|
android:foreground | 设置帧布局管理器的前景图像 |
android:foregroundGravity | 设置前景图像的 Gravity 属性,也就是显示的位置 |
样例
利用帧布局(FrameLayout),创建一个个长宽为等比数列且颜色各不相同的控件,由于后加进来的控件会覆盖在前一个控件上,就会出现如图所示的效果。实现代码如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="400px"
android:height="400px"
android:background="#f00"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="340px"
android:height="340px"
android:background="#0f0"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="280px"
android:height="280px"
android:background="#00f"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="220px"
android:height="220px"
android:background="#ff0"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="160px"
android:height="160px"
android:background="#f0f"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="100px"
android:height="100px"
android:background="#0ff"/>
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
表格布局管理器
表格布局管理器 TableLayout和 Excel 表格类似,是以行和列的性质管理放入的组件。在 TableLayout 中可以添加多个
xml 属性
FrameLayout 继承了 LinearLayout,因此它支持 LinearLayout 的 xml 属性,除此之外还支持常用 xml 属性如下所示。
xml 属性 | 说明 |
---|---|
android:collapseColumns | 设置需要被隐藏的列的列序号(从 0 开始),多个列序号之间用逗号分隔 |
android:shrinkColumns | 设置允许被收缩的列的列序号(从 0 开始),多个列序号之间用逗号分隔 |
android:stretchColumns | 设置允许被拉伸的列的列序号(从 0 开始),多个列序号之间用逗号分隔 |
一列可以同时具备 stretchColumns 及 shrinkColumns 属性,当该列的内容很多时,系统会自动调节该行的 layout height,以多行的形式显示其内容。每个单元格有如下 xml 属性。
xml 属性 | 说明 |
---|---|
android:layout_column | 指定该单元格在第几列显示 |
android:layout_span | 指定该单元格占据的列数,默认为 1 |
样例
在 TableLayout 中,首先列数为最多列的列数,且表格布局的子对象不能指定 layout_width 属性,永远是match_parent,不过子对象可以定义 layout_height 属性。但是根据要求宽度占满全屏,因此我们要使用属性 android:stretchColumns="0,1" ,设置可伸缩列横向扩展占满屏。指定显示在第几列要设置属性 android:layout_column,指定占据几列是设置属性
android:layout_span。关于控件内容中文字间的换行,应使用 "
"。
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="0,1"
app:layoutDescription="@xml/activity_main_scene"
tools:context=".MainActivity">
<TableRow>
<TextView
android:layout_margin="10dp"
android:background="@color/lightgray"
android:gravity="center"
android:text=" 第1行 第1列" />
<TextView
android:background="@color/lightgray"
android:layout_margin="10dp"
android:gravity="center"
android:text=" 第1行 第2列 " />
</TableRow>
<Button
android:layout_margin="10dp"
style="@style/ButtonStyle"
android:text="第2行 第1列:
单独的button,非TableRow"
app:strokeColor="#BAB6B6"></Button>
<TableRow>
<TextView
android:layout_column="1"
android:layout_margin="10dp"
android:background="@color/lightgray"
android:gravity="center"
android:text="第3行
指定到第2列"/>
</TableRow>
<TableRow>
<TextView
android:layout_column="0"
android:layout_margin="10dp"
android:background="@color/lightgray"
android:gravity="center"
android:text="第4行 指定到第1列" />
</TableRow>
<TableRow>
<TextView
android:gravity="center"
android:layout_span="2"
android:layout_height="fill_parent"
android:background="@color/lightgray"
android:layout_margin="10dp"
android:text="第5行 第1列 指定占据2列空间..." />
</TableRow>
</TableLayout>
网格布局管理器
网格布局管理器 GridLayout将屏幕划分为行和列的单元格,每个单元格放置一个组件。和 LinearLayout、TableLayout 不同在于,网格布局管理器跨行跨列非常方便,且整齐美观。
xml 属性
GridLayout 支持常用 xml 属性如下所示。
xml 属性 | 说明 |
---|---|
android:columnCount | 指定网格的最大列数 |
android:orientation | 当没有为放入其中的组件分配行和列时,指定其排列方式,可选 horizontal 和 vertical |
android:rowCount | 指定网格的最大行数 |
android:useDefaultMargins | 指定是否使用默认的边距,其属性值设置为 true 时表示使用 |
android:alignmentMode | 指定该布局管理器采用的对齐模式,alignBounds 对齐边界,alignMargins 对齐边距 |
android:rowOrderPreserved | 设置行边界显示的顺序和行索引的顺序是否相同,为 true 时表示相同 |
android:columnOrderPreserved | 设置列边界显示的顺序和列索引的顺序是否相同,为 true 时表示相同 |
为了控制网格布局管理器中各子组件的布局分布,网格布局管理器提供了 GridLayout.LayoutParams内部类,提供的 xml 属性如下所示。
xml 属性 | 说明 |
---|---|
android:layout_column | 指定该子组件位于网格的第几列 |
android:layout_columnSpan | 指定该子组件横向跨几列,索引从 0 开始 |
android:layout_column Weight | 指定该子组件在水平方向上的权重,即该组件分配水平剩余空间的比例 |
android:layout_gravity | 指定该子组件采用什么方式占据该网格的空间 |
android:layout row | 指定该子组件位于网格的第几行,索引从 0 开始 |
android:layout_rowSpan | 指定该子组件纵向跨几行 |
android:layout rowWeight | 指定该子组件在垂直方向上的权重,即该组件分配水平剩余空间的比例 |
如果想让某个组件跨行或跨列,需要先通过 android:layout columnSpan 或者 androidllayout rowSpan 设置跨越的行或列数,然后再设置其 layout gravity 属性为 fill。
样例
基于 GridLayout 设计一款计算器 App 的界面,可以将将计算机的按键看作一个个格子,有的按键比较大,可以使用跨行或跨列来表示。
<?xml version="1.0" encoding="utf-8"?>
<GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_row="7"
android:columnCount="4"
android:orientation="horizontal" >
<EditText
android:layout_columnSpan="4"
android:layout_gravity="fill"
android:layout_rowWeight="1"
android:layout_columnWeight="1"
/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="mc"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="m+"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="m-"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="mr"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="C"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="+/-"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="/"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="*"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="7"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="8"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="9"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="-"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="4"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="5"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="6"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="+"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="1"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="2"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="3"/>
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="="
android:layout_rowSpan="2"
android:layout_gravity="fill" />
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="0"
android:layout_columnSpan="2"
android:layout_gravity="fill" />
<Button
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:text="."/>
</GridLayout>
参考资料
《零基础学 Android》,明日科技编著,吉林大学出版社
《Android 移动应用开发》,杨谊 主编、喻德旷 副主编,人民邮电出版社