安卓应用使用层次结构的 View
和ViewGroup
对象建立图形用户界面。View
对象通常是用户界面小部件,例如 按钮 或 文本字段。ViewGroup
对象是不可见的视图容器,它定义了子视图的布局,例如网格或垂直列表。
安卓提供了与 View
和ViewGroup
的子类相对应的 XML 词汇表,你能在 XML 文件中使用层次结构的用户界面元素定义你的用户界面。
可选的布局
在 XML 文件中而不是在运行时代码中声明你的用户界面布局是非常有用的,这有几个原因,最重要的是你可以为不同的屏幕大小创建不同的布局。例如,你可以创建两个版本的布局,告诉系统小屏幕使用一个布局,大屏幕使用另一个布局。更多信息,参见支持不同的设备。
图 1. ViewGroup
对象在布局中包含其他 View
对象形成分支结构示意图。
在这节课中,你将在 XML 文件中创建一个包含文本字段和按钮的布局。在下节课中,你将学习当按钮按下时发送文本字段内容到另一个 Activity。
创建线性布局
打开 res/layout/
目录中的 activity_main.xml
文件。
注意: 在Eclipse中,当你打开一个布局文件,最初显示的是一个图形化的布局编辑器。 这个编辑器使用 WYSIWYG 工具帮助你创建布局。在这节课,你要直接操作 XML,所以点击屏幕底部的activity_main.xml 选项卡打开 XML 编辑器。
你创建工程时选择的 BlankActivity 模板包含 activity_main.xml
文件, 这个文件包含一个 RelativeLayout
根视图和一个TextView
子视图。
首先,删除 <TextView>
元素并把<RelativeLayout>
元素改为<LinearLayout>
。然后添加android:orientation
属性并把值设为"horizontal"
。 结果看起来像这样:
<?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:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > </LinearLayout>
LinearLayout
是一个视图组(ViewGroup
的一个子类),它根据 android:orientation
属性所指定的在垂直或水平方向排列子视图。LinearLayout
的每个孩子根据它们在 XML 文件中出现的顺序在屏幕上展示。
另外两个属性,android:layout_width
和android:layout_height
,所有视图都需要用它们来指定大小。
因为 LinearLayout
是布局的根视图,它需要把宽度和高度都设置成"match_parent"
来充满应用程序可用的整个屏幕区域。这个值表明视图需要扩展它的宽度和高度直至与它的父视图的宽度和高度相同。
更多关于布局属性的信息,参见 布局指南。
添加文本字段
在 <LinearLayout>
中添加一个<EditText>
元素,创建一个用户可编辑的文本字段。
像每个 View
对象,你必须定义一些 XML 属性来指定EditText
对象的属性。下面是怎样在<LinearLayout>
元素中定义属性:
<EditText android:id="@+id/edit_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="@string/edit_message" />
资源对象是一个唯一的整数名称,它与应用的一个资源(比如位图,布局文件,或字符串)相关。
你的工程中的 gen/R.java
文件为每个资源定义一个对应的资源对象。你可以使用R
类中的对象名称来引用你的资源,比如你需要为android:hint
属性指定一个字符串值。你还可以创建任意的资源 ID,然后使用android:id
属性与视图关联, 这允许你在其他代码中引用那个视图。
每次编译你的应用时,SDK 工具都会生成 R.java
。你永远都不应该手工修改这个文件。
更多信息,参见 提供资源指南。
关于这些属性:
-
为视图提供一个唯一标识符,你可以再代码中使用它引用对象,比如读取或操作这个对象(你会在下节课中看到这些)。
你在 XML 中引用任何资源对象时都需要 at 符号(
@
)。它后面跟着资源类型(这个例子中是id
),一个斜杠,然后是资源名称(edit_message
)。当你第一次定义一个资源 ID 时,资源类型前面才需要有加号(
+
)。当你编译应用时,SDK 工具使用这个 ID 名称在你的工程的gen/R.java
文件中创建一个引用EditText
元素的新的资源。一旦用这种方式定义了资源 ID,其他对这个 ID 的引用都不需要加号。只有在指定新的资源 ID 时才需要使用加号,具体资源(例如字符串或布局)不需要加号。更多关于资源对象的信息请阅读旁边的说明框。 -
不直接为宽度和高度指定具体大小,值
"wrap_content"
指定视图的大小只需要适合它的内容。如果你使用"match_parent"
,那么元素会充满EditText
屏幕,因为它会匹配父LinearLayout
的大小。更多信息,参见 布局指南 。 -
当文本字段为空时默认显示这个字符串。不是使用一个硬编码的字符串作为值,值
"@string/edit_message"
引用在一个单独文件中定义的字符串资源。因为它引用一个具体资源(不仅仅一个标识符),它不需要加号。但是,因为你还没有定义这个字符串资源,起初你会看到一个编译错误。在下一小节你会定义这个字符串来修正这个错误。注意: 这个字符串资源的名称和元素 ID
edit_message
相同。但是,资源引用的作用域是资源类型(例如id
或string
), 所以使用相同的名称并不会导致冲突。
android:id
android:layout_width
和
android:layout_height
android:hint
添加字符串资源
当你需要在用户界面添加文本时,你应该总是把每个字符串指定成一个资源。字符串资源允许你在一个地方维护所有的用户界面文本,这样就很容易查找和更新文本。字符串外部化还允许你为每个字符串资源提供可选的定义,从而使你的应用本地化为不同的语言。
默认地,你的安卓工程包含一个字符串资源文件 res/values/strings.xml
。添加一个新的名称为"edit_message"
的字符串并把值设置为 "Enter a message." (你可以删除 "hello_world" 字符串。)
当你在这个文件中时,同样为你将要添加的按钮添加一个 "Send" 字符串,名称为 "button_send"
。
strings.xml
修改后的结果看起来像这样:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">My First App</string> <string name="edit_message">Enter a message</string> <string name="button_send">Send</string> <string name="action_settings">Settings</string> <string name="title_activity_main">MainActivity</string> </resources>
关于使用字符串资源为其他语言本地化你的应用的更多信息,参见 支持不同的设备。
添加按钮
现在在布局中紧跟在 <EditText>
元素后面,添加一个<Button>
:
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_send" />
高度和宽度设置成 "wrap_content"
所以按钮仅与它需要适合的文本一样大。这个按钮不需要android:id
属性,因为它不会被 activity 代码引用。
使输入框充满屏幕宽度
刚才设计的布局中,EditText
和Button
控件都只和它们需要适合的内容一样大,就像 图 2 所展示的。
图 2. 宽度设置为"wrap_content"
的EditText
和Button
控件。
这对于按钮工作得很好,但对于文本字段就不太好了,因为用户可能输入一些比较长的内容。所以,文本字段充满未使用的屏幕宽度将会更好。你可以在 LinearLayout
中使用权重属性来这样做,使用android:layout_weight
属性指定权重。
权重的值是一个数字,它指定了每个视图需要占用的剩余可用空间, 相对于兄弟视图占用的空间。这有点像饮料原料配方:“2份伏特加,1份咖啡香甜酒” 意味着饮料的三分之二是伏特加。例如,如果你给一个视图权重2,给另一个视图权重1,和为3,那第一个视图充满剩余空间的 2/3,第二个视图充满其余剩余空间。如果你添加了第三个视图并给它权重1,那第一个视图(权重2)现在得到剩余空间的1/2,另外两个视图各得1/4。
所有视图的默认权重为0,所以如果你只给一个视图指定一个大于0的任意权重,那这个视图将获得在所有其他视图获得它们所需空间后剩余的全部空间。所以,为了让 EditText
元素充满你的布局的剩余空间,给它权重1并且不给按钮设置权重。
<EditText android:layout_weight="1" ... />
为了提高指定权重时布局的性能,你需要把 EditText
的宽度改为0(0dp)。把宽度设为0能提高布局性能,因为使用"wrap_content"
作为宽度 需要系统计算一个最终不相关的宽度,因为这个宽度值需要另外计算来充满剩余空间。
<EditText android:layout_weight="1" android:layout_width="0dp" ... />
图 3 显示了当你把所有权重都分配给 EditText
元素时的结果。
图 3. EditText
控件拥有所有布局权重,充满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:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <EditText android:id="@+id/edit_message" android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:hint="@string/edit_message" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_send" /> </LinearLayout>
当你创建这个工程时 SDK 工具生成的默认的 Activity
类采用了这个布局,所以你可以直接运行应用查看结果:
- 在 Eclipse 中,点击工具栏上的 Run 。
- 或者在命令行中,改变目录到你的安卓工程的根目录,执行:
ant debug adb install bin/MyFirstApp-debug.apk
继续下一课,学习怎样响应按钮按下事件,读取文本字段内容,启动另一个 activity,以及更多其他内容。