3.3 常用布局
本节介绍常见的几种布局用法,包括在某个方向上顺序排列的线性布局,参照其他视图的位置相对排列的相对布局,像表格那样分行分列显示的网格布局,以及支持通过滑动操作拉出更多内容的滚动视图。
3.3.1 线性布局LinearLayout
前几个小节的例程中,XML文件用到了LinearLayout布局,它的学名为线性布局。顾名思义,线性布局像是用一根线把它的内部视图串起来,故而内部视图之间的排列顺序是固定的,要么从左到右排列,要么从上到下排列。在XML文件中,LinearLayout通过属性android:orientation区分两种方向,其中从左到右排列叫作水平方向,属性值为horizontal;从上到下排列叫作垂直方向,属性值为vertical。如果LinearLayout标签不指定具体方向,则系统默认该布局为水平方向排列,也就是默认除了方向之外,线性布局还有一个权重概念,所谓权重,指的是线性布局的下级视图各自拥有多大比例的宽高。
<?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">
<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="横排第一个"
android:textSize="17sp"
android:textColor="#000000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="横排第二个"
android:textSize="17sp"
android:textColor="#000000"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="竖排第一个"
android:textSize="17sp"
android:textColor="#000000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="竖排第二个"
android:textSize="17sp"
android:textColor="#000000"/>
</LinearLayout>
</LinearLayout>
<?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">
<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="横排第一个"
android:textSize="17sp"
android:textColor="#000000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="横排第二个"
android:textSize="17sp"
android:textColor="#000000"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="竖排第一个"
android:textSize="17sp"
android:textColor="#000000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="竖排第二个"
android:textSize="17sp"
android:textColor="#000000"/>
</LinearLayout>
</LinearLayout>
3.3.2 相对布局RelativeLayout
线性布局的下级视图是顺序排列着的,另一种相对布局的下级视图位置则由其他视图决定。相对布局名为RelativeLayout,因为下级视图的位置是相对位置,所以得有具体的参照物才能确定最终位置。如果不设定下级视图的参照物,那么下级视图默认显示在RelativeLayout内部的左上角。用于确定下级视图位置的参照物分两种,一种是与该视图自身平级的视图;另一种是该视图的上级视图(也就是它归属的RelativeLayout)。综合两种参照物,相对位置在XML文件中的属性名称说明见表。
这里将这些属性分成组,便于理解和记忆。
a)、第一类:属性值为true或false
android:layout_centerHrizontal 水平居中
android:layout_centerVertical 垂直居中
android:layout_centerInparent 相对于父元素完全居中
android:layout_alignParentBottom 贴紧父元素的下边缘
android:layout_alignParentLeft 贴紧父元素的左边缘
android:layout_alignParentRight 贴紧父元素的右边缘
android:layout_alignParentTop 贴紧父元素的上边缘
b)、第二类:属性值必须为id的引用名“@id/id-name”
android:layout_below 在某元素的下方
android:layout_above 在某元素的的上方
android:layout_toLeftOf 在某元素的左边
android:layout_toRightOf 在某元素的右边
android:layout_alignTop 本元素的上边缘和某元素的的上边缘对齐
android:layout_alignLeft 本元素的左边缘和某元素的的左边缘对齐
android:layout_alignBottom 本元素的下边缘和某元素的的下边缘对齐
android:layout_alignRight 本元素的右边缘和某元素的的右边缘对齐
c)、第三类:属性值为具体的像素值,如30dip,40px
android:layout_marginBottom 离某元素底边缘的距离
android:layout_marginLeft 离某元素左边缘的距离
android:layout_marginRight 离某元素右边缘的距离
android:layout_marginTop 离某元素上边缘的距离
<?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="250dp">
<TextView
android:id="@+id/tv_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="#EF3A3A"
android:text="我在中间"
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:background="#ffffff"
android:text="水平中间"
android:textColor="#000000"
android:textSize="11sp" />
<TextView
android:id="@+id/tv_center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:background="#ffffff"
android:text="我在垂直中间"
android:textColor="#000000"
android:textSize="11sp" />
<TextView
android:id="@+id/tv_parent_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:background="#ffffff"
android:text="我跟上级左边对齐"
android:textColor="#000000"
android:textSize="11sp" />
<TextView
android:id="@+id/tv_parent_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="#ffffff"
android:text="我跟上级右边对齐"
android:textColor="#000000"
android:textSize="11sp" />
<TextView
android:id="@+id/tv_parent_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#ffffff"
android:text="我跟上级顶部对齐"
android:textColor="#000000"
android:textSize="11sp" />
<TextView
android:id="@+id/tv_parent_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#ffffff"
android:text="我跟上级底部对齐"
android:textColor="#000000"
android:textSize="11sp" />
<TextView
android:id="@+id/tv_left_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/tv_center"
android:layout_alignTop="@id/tv_center"
android:background="#ffffff"
android:text="我在中间左边"
android:textColor="#009688"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_right_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/tv_center"
android:layout_alignBottom="@id/tv_center"
android:background="#ffffff"
android:text="我在中间右边"
android:textColor="#FF5722"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_above_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/tv_center"
android:layout_alignLeft="@id/tv_center"
android:background="#ffffff"
android:text="我在中间上面"
android:textColor="#FFEB3B"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_below_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_center"
android:layout_alignRight="@id/tv_center"
android:background="#ffffff"
android:text="我在中间下面"
android:textColor="#FFEB3B"
android:textSize="20sp" />
</RelativeLayout>
3.3.3 网格布局GridLayout
虽然线性布局既能在水平方向排列,也能在垂直方向排列,但它不支持多行多列的布局方式,只支持单行(水平排列)或单列(垂直排列)的布局方式。若要实现类似表格那样的多行多列形式,可采用网格布局GridLayout。 网格布局默认从左往右、从上到下排列,它先从第一行从左往右放置下级视图,塞满之后另起一行放置其余的下级视图,如此循环往复直至所有下级视图都放置完毕。为了判断能够容纳几行几列,网格布局新增了android:columnCount与android:rowCount两个属性,其中columnCount指定了网格的列数,即每行能放多少个视图;rowCount指定了网格的行数,即每列能放多少个视图。
下面是运用网格布局的XML布局样例,它规定了一个两行两列的网格布局,且内部容纳四个文本视图。
<?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:columnCount="2"
android:rowCount="2">
<TextView
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_columnWeight="1"
android:background="#ffcccc"
android:gravity="center"
android:text="浅红色"
android:textColor="#000000"
android:textSize="17sp" />
<TextView
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_columnWeight="1"
android:background="#ffaa00"
android:gravity="center"
android:text="橙色"
android:textColor="#000000"
android:textSize="17sp" />
<TextView
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_columnWeight="1"
android:background="#00ff00"
android:gravity="center"
android:text="绿色"
android:textColor="#000000"
android:textSize="17sp" />
<TextView
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_columnWeight="1"
android:background="#660066"
android:gravity="center"
android:text="深紫色"
android:textColor="#000000"
android:textSize="17sp" />
</GridLayout>
3.3.4 滚动视图ScrollView
手机屏幕的显示空间有限,常常需要上下滑动或左右滑动才能拉出其余页面内容,可惜一般的布局节点都不支持自行滚动,这时就要借助滚动视图了。与线性布局类似,滚动视图也分为垂直方向和水平方向两类,其中垂直滚动视图名为ScrollView,水平滚动视图名为HorizontalScrollView。这两个滚动视图的使用并不复杂,主要注意以下 3 点:
( 1 )垂直方向滚动时,layout_width属性值设置为match_parent,layout_height属性值设置为wrap_content。
( 2 )水平方向滚动时,layout_width属性值设置为wrap_content,layout_height属性值设置为match_parent。
( 3 )滚动视图节点下面必须且只能挂着一个子布局节点,否则会在运行时报错Caused by:java.lang.IllegalStateException:ScrollView can host only one direct child。
<?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">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="200dp">
<!-- 水平方向的线性布局,两个子视图的颜色分别为青色和黄色 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<View
android:layout_width="300dp"
android:layout_height="match_parent"
android:background="#aaffff"/>
<View
android:layout_width="300dp"
android:layout_height="match_parent"
android:background="#ffff00"/>
</LinearLayout>
</HorizontalScrollView>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 垂直方向的线性布局,两个子视图的颜色分别为绿色和橙色 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#00ff00"/>
<View
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#ffffaa"/>
</LinearLayout>
</ScrollView>
</LinearLayout>