布局定义用户界面的视觉结构,如Activity或应用小部件的 UI。可以通过两种方式声明布局:
i.在 XML 中声明 UI 元素。Android 提供了对应于 View 类及其子类的简明 XML 词汇,如用于小部件和布局的词汇;
ii.运行时实例化布局元素。应用可以通过编程创建 View 对象和 ViewGroup 对象(并操纵其属性)。
Android 框架让你可以灵活地使用以下一种或两种方法来声明和管理应用的 UI。例如,您可以在 XML 中声明应用的默认布局,包括将出现在布局中的屏幕元素及其属性。然后,您可以在应用中添加可在运行时修改屏幕对象(包括那些已在 XML 中声明的对象)状态的代码。
您还应尝试使用层次结构查看器工具来调试布局—当您在模拟器或设备上进行调试时,它会显示布局属性值、绘制具有内边距/外边距指示符的线框以及完整渲染视图。
可以利用 layoutopt 工具快速分析布局和层次结构中是否存在低效环节或其他问题。
在 XML 中声明 UI 的优点在于,您可以更好地将应用的外观与控制应用行为的代码隔离。您的 UI 描述位于应用代码外部,这意味着您在修改或调整描述时无需修改您的源代码并重新编译。例如,你可以创建适用于不同屏幕方向、不同设备屏幕尺寸和不同语言的 XML 布局。此外,在 XML 中声明布局还能更轻松地显示 UI 的结构,从而简化问题调试过程。
一般而言,用于声明 UI 元素的 XML 词汇严格遵循类和方法的结构和命名方式,其中元素名称对应于类名称,属性名称对应于方法。实际上,这种对应关系往往非常直接,让您可以猜到对应于类方法的 XML 属性,或对应于给定 XML 元素的类。但请注意,并非所有词汇都完全相同。在某些情况下,在命名上略有差异。例如,EditText 元素具有的 text 属性对应的类方法是 EditText.setText()。
编译应用时,每个 XML 布局文件都会编译到一个 View 资源中。 在 Activity.onCreate() 回调实现中从应用代码加载布局资源。通过调用 setContentView(),以 R.layout.layout_file_name 形式向其传递对布局资源的引用来执行此操作。例如,如果你的XML 布局保存为 main_layout.xml,则需要像下面这样为你的 Activity 加载该布局:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
}
启动您的 Activity 时,Android 框架会调用 Activity 中的 onCreate() 回调方法
任何视图对象都可能具有关联的整型 ID,此 ID 用于在结构树中对 View 对象进行唯一标识。编译应用后,此 ID 将作为整型数引用,但在布局 XML 文件中,通常会在 id 属性中为该 ID 赋予字符串值。这是所有 View 对象共用的 XML 属性(由 View 类定义),您会经常用到它。XML 标记内部的 ID 语法是:
android:id="@+id/my_button"
字符串开头处的 @ 符号指示 XML 解析程序应该解析并展开 ID 字符串的其余部分,并将其标识为 ID 资源。加号 (+) 表示这是一个新的资源名称,必须创建该名称并将其添加到我们的资源(在 R.java 文件中)内。Android 框架还提供了许多其他 ID 资源。 引用 Android 资源 ID 时,不需要加号,但必须添加 android 软件包命名空间,如下所示:
android:id="@android:id/empty"
添加 android 软件包命名空间之后,现在,我们将从 android.R 资源类而非本地资源类引用 ID。
要想创建视图并从应用中引用它们,常见的模式是:
在布局文件中定义一个视图/小部件,并为其分配一个唯一的 ID:
然后创建一个 view 对象实例,并从布局中捕获它(通常使用 onCreate() 方法):
Button myButton = (Button) findViewById(R.id.my_button);
创建 RelativeLayout 时,为 view 对象定义 ID 非常重要。在相对布局中,同级视图可以定义其相对于其他同级视图的布局,同级视图通过唯一的 ID 进行引用。
ID 不需要在整个结构树中具有唯一性,但在您要搜索的结构树部分应具有唯一性(要搜索的部分往往是整个结构树,因此最好尽可能具有全局唯一性)。
a)线性布局LinearLayout
一种使用单个水平行或垂直行来组织子项的布局。它会在窗口长度超出屏幕长度时创建一个滚动条。
LinearLayout 是一个视图组,用于使所有子视图在单个方向(垂直或水平)保持对齐。 使用
android:orientation
属性指定布局方向。
如下面的代码是线性布局中包含着三个button视图,指定android:orientation="horizontal"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.geekp.layout.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮1" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮2" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮3" />
LinearLayout>
则这三个button水平排布:
如果指定属性:android:orientation="vertical"
则有如下效果:
LinearLayout 还支持使用 android:layout_weight 属性为各个子视图分配权重。此属性根据视图应在屏幕上占据的空间量向视图分配“重要性”值。 权重值更大的视图可以填充父视图中任何剩余的空间。子视图可以指定权重值,然后系统会按照子视图声明的权重值的比例,将视图组中的任何剩余空间分配给子视图。 默认权重为零。
下面就是将三个button视图赋予不同的权重:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:text="按钮1" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:text="按钮2" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="按钮3" />
结果就是:前两个按钮仅仅占据其内容所需的空间,第三个按钮将填充父布局剩余的空间。
b)相对布局Relative Layout
相对布局能够指定子对象彼此之间的相对位置(子对象 A 在子对象 B 左侧)或子对象与父对象的相对位置(与父对象顶部对齐)。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp">
<EditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/dates"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/name"
android:layout_toLeftOf="@+id/times"
android:text="2017年2月20日" />
<TextView
android:id="@id/times"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/name"
android:text="11:11:45" />
<Button
android:layout_width="96dp"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/times"
android:text="done" />
RelativeLayout>
下面的布局就指示了id为date的text view位于id为name的下方同时位于父容器的左侧;id为time的textview位于id为name的下方且位于父容器的右侧;button则位于id为time的正下方;
最为常见的也是以上两种布局,下面是不常用的布局
3.约束布局ConstraintLayout
ConstraintLayout允许您使用平面视图层次结构(无嵌套视图组)创建大而复杂的布局。它类似于RelativeLayout,所有视图根据兄弟视图和父布局之间的关系布局,但它比RelativeLayout更灵活,更容易使用Android Studio的布局编辑器。
您可以使用ConstraintLayout做的一切都可以直接从布局编辑器的可视化工具中获得,因为布局API和布局编辑器是专门为彼此构建的。因此,您可以通过拖放而不是编辑XML来完全使用ConstraintLayout来构建布局。
下面是一个例子,将两个button进行横向布局:
从GIF中我们可以看到,这种布局只需要在Android studio中对视图进行简单地拖拽,Android studio就会自动为我们生成布局XML文件:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮2"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="8dp"
app:layout_constraintLeft_toRightOf="@+id/button"
android:layout_marginLeft="8dp"
android:layout_marginEnd="16dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginRight="16dp" />
有关这种布局我再这里不再赘述,详细请点击
4.绝对布局
绝对布局中将所有的子元素通过设置android:layout_x 和 android:layout_y属性,将子元素的坐标位置固定下来,即坐标(android:layout_x, android:layout_y) ,layout_x用来表示横坐标,layout_y用来表示纵坐标。屏幕左上角为坐标(0,0),横向往右为正方,纵向往下为正方。实际应用中,这种布局用的比较少,因为Android终端一般机型比较多,各自的屏幕大小。分辨率等可能都不一样,如果用绝对布局,可能导致在有的终端上显示不全等。
这种布局已经被Android官网弃用,不建议使用:
5.帧布局FrameLayout
FrameLayout设计用于屏蔽屏幕上的一个区域以显示单个项目。通常,FrameLayout应该用于保存单个子视图,因为可能难以以可扩展到不同屏幕尺寸的方式组织子视图,而不会使子节点相互重叠。然而,你可以添加多个孩子到FrameLayout,并通过使用android:layout_gravity属性为每个孩子分配重力来控制它们在FrameLayout中的位置。
子视图在堆栈中绘制,最近添加的子节点在顶部。 FrameLayout的大小是它最大的孩子(加上填充)的大小,可见或不可见(如果FrameLayout的父允许)。仅当setConsiderGoneChildrenWhenMeasuring()设置为true时,才使用GONE的视图进行大小调整。
例如下面的代码的效果为
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:layout_width="250dp"
android:layout_height="205dp"
android:background="@color/colorAccent"
android:text="按钮1" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮2" />
FrameLayout>