布局是一种可用于放置很多控件的容器,其可以按照一定的规律调整内部控件的位置。而布局的内部除了可以放置控件外,还可以放置布局,通过多层布局的嵌套,就能够完成一些比较复杂的界面实现。
LinearLayout
LinearLayout也称为线性布局,该布局会将其所包含的控件在线性方向上一次排列。
而既然是线性排列,肯定就不止一个方向,比如可以设置android:orientation属性来指定排列方向是vertical还是horizontal。
<?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">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 2" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 3" />
</LinearLayout>
上面的代码中,在LinearLayout中添加了3个Button,每个Button的长和宽都是wrap_content,并指定了排列方向为vertical,程序运行结果为:
修改LinearLayout的排列方向后的结果为:
需要注意的是,如果不指定android:orientation属性,默认的排列方向就是horizontal。同时如果是水平排列的话,内部控件的宽度就不能够指定为match_parent,否则,单独一个控件就会将整个水平方向占满,其它控件就没有空间放置了。同样的道理,如果是垂直排列的话,内部控件的高度就不能够指定为match_parent,否则,单独一个控件就会将整个垂直方向占满,其它控件就没有空间放置了。
而android:layout_gravity属性则可以指定控件在布局中的对齐方式,其可选值和android:gravity属性类似。需要注意的是,当LinearLayout为水平排列时,只有垂直方向上的对齐方式才会生效,因为此时水平方向上的长度是不固定的,每添加一个控件,水平方向上的长度都会改变,因此无法指定该方向上的对齐方式。同样的道理,当LinearLayout为垂直排列时,只有水平方向上的对齐方式才会生效,因为此时垂直方向上的长度是不固定的,每添加一个控件,垂直方向上的长度都会改变,因此无法指定该方向上的对齐方式。
修改上面按钮的对齐方式:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:text="Button 1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="Button 2" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="Button 3" />
</LinearLayout>
运行结果为:
因为布局内控件是水平排列,因此整个对齐方式依此为顶部/居中/底部对齐。
而android:layout_weight则允许以比例形式指定控件大小,这在手机屏幕的适配性方面可以起到很重要的作用。比如消息发送界面通常有一个文本编辑框和发送按钮:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/input_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Type something"
tools:ignore="Suspicious0dp" />
<Button
android:id="@+id/send"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Send"
tools:ignore="Suspicious0dp" />
</LinearLayout>
上面代码中,将EditText和Button的宽度都指定为了0dp,并使用android:layout_weight指定了在水平方向上宽度所占的权重。
这里宽度权重分配方式为:系统先将LinearLayout下所有控件指定的权重值相加,得到一个总值,然后每个控件所占大小的比例就是其自身的权重值除以总值。
程序运行结果为:
而实际开发中,本文编辑框通常是较长的,而发送按钮通常是较短的,一般发送按钮能够容纳其自身长度即可,因此代码可能修改为:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/input_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Type something"
tools:ignore="Suspicious0dp" />
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Send"
tools:ignore="Suspicious0dp" />
</LinearLayout>
在上面的代码中,按钮宽度保持wrap_content,即容纳自身大小,而文本编辑框则占满剩下的控件,因此也就独占权重。
程序运行结果为:
RelativeLayout
RelativeLayout又称为相对布局,也是一种比较常用的布局。该布局可以通过相对定位的方式让控件出现在布局的任何位置。
<?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">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Button 1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="Button 2" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Button 3" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="Button 4" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="Button 5" />
</RelativeLayout>
以上的代码也没什么不好理解的地方,分别放置5个按钮在5个地方。程序运行结果为:
上面例子中的每个控件都是相对于父布局进行定位的,当然也可以相对于控件进行定位:
<?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">
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Button 3" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/button3"
android:layout_toLeftOf="@id/button3"
android:text="Button 1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/button3"
android:layout_toRightOf="@id/button3"
android:text="Button 2" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/button3"
android:layout_toLeftOf="@id/button3"
android:text="Button 4" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/button3"
android:layout_toRightOf="@id/button3"
android:text="Button 5" />
</RelativeLayout>
上面的代码也很好理解。程序运行结果为:
RelativeLayout中还有另外一组相对于控件进行定位的属性:
- android:layout_alignLeft:表示让一个控件的左边缘和另一个控件的左边缘对齐
- android:layout_alignRight:表示让一个控件的右边缘和另一个控件的右边缘对齐
- android:layout_alignTop:表示让一个控件的上边缘和另一个控件的上边缘对齐
- android:layout_alignBottom:表示让一个控件的下边缘和另一个控件的下边缘对齐
FrameLayout
FrameLayout又称为帧布局,该布局没有丰富的定位方式,所有的控件都会默认摆放在布局的左上角,相对来说应用场景较少。
<?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">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is TextView"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</FrameLayout>
运行结果为:
可以看出,文字和按钮都在布局的左上角。而由于按钮在文字之后添加,因此按钮会覆盖文字。
而除了这种默认效果之外,还可以使用layout_gravity属性来指定控件在布局中的对齐方式,这和LinearLayout中的用法是相似的。
<?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">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="This is TextView"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="Button" />
</FrameLayout>
程序运行结果为:
总体来说,由于定位方式的欠缺,该布局的应用场景相对偏少。