此 Codelab 是“Android Kotlin 基础知识”课程的一部分。如果您按顺序学习这些 Codelab,您将会充分发掘此课程的价值。“Android Kotlin 基础知识”Codelab 着陆页列出了所有课程 Codelab。
简介
到目前为止,您已完成所有设置,Android Studio 也为您创建了许多代码。在修改所有这些代码之前,请务必了解您刚刚创建的内容以及如何浏览 Android 应用的源文件。
在此 Codelab 中,您将详细了解 Android 应用的主要组件,并向应用添加简单的按钮互动功能。
您应当已掌握的内容
- 如何安装和打开 Android Studio。
- 如何创建新的应用项目。
- 了解如何在模拟器或实体设备上运行应用。
学习内容
- 如何修改应用的布局文件。
- 如何创建具有互动行为的应用。
- 许多新术语。如需了解术语和概念的通俗易懂的说明,请参阅词汇术语库。
操作内容
- 探索
MainActivity
Kotlin 文件和 activity 的布局文件。 - 在 XML 中修改 activity 的布局。
- 向 activity 的布局添加一个
Button
元素。 - 将硬编码的字符串提取到字符串资源文件中。
- 实现点击处理程序方法,以便在用户点按
Button
时在屏幕上显示消息。
在此 Codelab 中,您将创建一个名为 DiceRoller 的新应用项目,并添加带有按钮的基本互动功能。每次点击按钮时,所显示文本的值都会发生变化。此 Codelab 的最终 DiceRoller 应用如下所示:
在上一个 Codelab 中,您了解了应用项目的主要部分,包括 java
和 res
目录。在此任务中,您将重点介绍构成应用的两大最重要的文件:MainActivity
Kotlin 文件和 activity_main.xml
布局文件。
第 1 步:检查 MainActivity
MainActivity
是 Activity
的一个示例。Activity
是一个核心 Android 类,用于绘制 Android 应用界面 (UI) 并接收输入事件。当应用启动时,它会启动 AndroidManifest.xml
文件中指定的 activity。
许多编程语言都定义了一个启动程序的主方法。Android 应用没有 main 方法。相反,AndroidManifest.xml
文件表示当用户点按应用的启动器图标时,应启动 MainActivity
。为了启动 activity,Android 操作系统会使用清单中的信息来设置应用的环境并构建 MainActivity
。然后,MainActivity
会依次执行一些设置。
每个 activity 都有一个关联的布局文件。activity 和布局通过一个称为布局扩充的过程连接在一起。当 activity 启动时,XML 布局文件中定义的视图会转换为内存中的 Kotlin 视图对象(或“扩充”为 Kotlin 视图对象)。发生这种情况后,activity 可以将这些对象绘制到屏幕上,还可以动态修改它们。
- 在 Android Studio 中,依次选择 File > New > New Project 以创建新项目。使用 Empty activity,然后点击 Next。
- 调用项目 DiceRoller,并验证项目名称、项目位置的所有其他值。确保“Use AndroidX Artifacts”处于选中状态。点击完成。
- 在 Project > Android 窗格中,展开 java > com.example.android.diceroller。双击 MainActivity。代码编辑器显示了
MainActivity
中的代码。 - 在软件包名称和 import 语句下方是
MainActivity
的类声明。MainActivity
类扩展AppCompatActivity
。
class MainActivity : AppCompatActivity() { ...
- 请注意
onCreate()
方法。activity 不使用构造函数来初始化对象。相反,系统会在 activity 设置过程中调用一系列预定义的方法(称为“生命周期方法”)。其中一个生命周期方法是onCreate()
,您始终会在自己的应用中替换该方法。您将在后面的 Codelab 中详细了解生命周期方法。
在onCreate()
中,您可以指定与 activity 关联的布局,并扩充该布局。setContentView()
方法会同时执行这两项操作。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
setContentView()
方法使用 R.layout.activity_main
引用布局,而 R.layout.activity_main
实际上是一个整数引用。R
类是在您构建应用时生成的。R
类包含应用的所有资源,包括 res
目录的内容。
在本例中,R.layout.activity_main
指的是生成的 R
类、layout
文件夹和 activity_main.xml
布局文件。(资源不包含文件扩展名。)您将使用 R
类中的类似引用来引用应用的许多资源(包括图片、字符串和布局文件中的元素)。
第 2 步:检查并探索应用布局文件
应用中的所有 activity 在应用的 res/layout
目录中都有关联的布局文件。布局文件是一个 XML 文件,用于表达 activity 的实际外观。布局文件通过定义视图以及定义视图在屏幕上的显示位置来实现此目的。
视图是指扩展了 View
类的文本、图片和按钮等内容。视图类型有很多,包括 TextView
、Button
、ImageView
和 CheckBox
。
在此任务中,您将检查并修改应用布局文件。
- 在 Project > Android 窗格中,展开 res > layout,然后双击 activity_main.xml。系统随即会打开布局设计编辑器。Android Studio 包含此编辑器,可让您以可视化方式构建应用的布局并预览布局设计。在后续的 Codelab 中,您将详细了解设计编辑器。
- 如需以 XML 格式查看布局文件,请点击窗口底部的 Text 标签。
- 删除布局编辑器中的所有现有 XML 代码。如果您使用的是 Android Studio 设计编辑器,那么新项目随附的默认布局是一个不错的起点。在本课程中,您将使用底层 XML 从头开始构建新布局。
- 将此代码复制并粘贴到布局中:
<?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="wrap_content"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
现在,我们来检查一下代码:
- 布局的顶层或根元素是
<LinearLayout>
元素。LinearLayout
视图是一个ViewGroup
。视图组是包含其他视图的容器,有助于指定视图在屏幕上的位置。
您添加到布局中的所有视图和视图组都以视图层次结构的形式进行组织,其中最顶层的 XML 元素是该层次结构的根。根视图可以包含其他视图和视图组,而所包含的视图组可以包含其他视图和视图组。当应用运行 XML 布局文件中的视图层次结构时,布局扩充后,该层次结构会变成对象层次结构。在这种情况下,根视图组是一个线性布局,用于以线性方式(垂直或水平)组织其子视图。
新 Android 项目的默认根元素是ConstraintLayout
,它与设计编辑器配合使用效果很好。对于此应用,您将使用比约束布局更简单的LinearLayout
视图组。在下一课中,您将详细了解视图组和 ConstraintLayout。 - 在
LinearLayout
标记内,注意android:layout_width
属性。此LinearLayout
的宽度设置为match parent
,这使其宽度与其父级相同。由于这是根视图,因此布局会展开到屏幕的完整宽度。 - 请注意,
android:layout_height
属性设置为wrap_content
。此属性可使LinearLayout
的高度与其包含的所有视图(目前只有TextView
)的总高度一致。 - 检查
<TextView>
元素。此TextView
用于显示文本,是 DiceRoller 应用中唯一的视觉元素。android:text
属性包含要显示的实际字符串,在本例中为字符串"Hello World!"
- 请注意
<TextView>
元素中的android:layout_width
和android:layout_height
属性,它们均设置为wrap_content
。文本视图的内容就是文本本身,因此该视图只会占用文本所需的空间。
如果用户无法掷骰子并查看掷出的点数,那么掷骰子应用就没什么用。首先,向布局添加一个用于掷骰子的按钮,并添加用于显示用户掷出的骰子值的文本。
第 1 步:向布局添加按钮
- 在文本视图下方的布局中添加一个
Button
元素,方法是输入 <Button,然后按回车键。系统会显示一个以/>
结尾并包含layout_width
和layout_height
属性的Button
块。
<Button
android:layout_width=""
android:layout_height="" />
- 将
layout_width
和layout_height
属性均设置为"wrap_content"
。使用这些值时,按钮的宽度和高度与其中包含的文本标签相同。 - 为按钮添加
android:text
属性,并将其值设为“Roll”。Button 元素现在如下所示:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Roll" />
对于 Button
视图,text
属性是按钮的标签。在布局编辑器中,该属性会以黄色突出显示,表示提示或警告。在本例中,黄色突出显示是因为字符串 "Roll"
硬编码在按钮标签中,但该字符串应为资源。您将在下一部分中了解字符串资源。
第 2 步:提取字符串资源
最好将应用的所有字符串都放在一个单独的文件中,而不是将字符串硬编码到布局或代码文件中。该文件名为 strings.xml
,位于应用的资源中,即 res/values/
目录中。
将字符串放在单独的文件中可让您更轻松地管理它们,尤其是在您多次使用这些字符串的情况下。此外,字符串资源对于翻译和本地化应用来说是必需的,因为您需要为每种语言创建一个字符串资源文件。
Android Studio 会通过提示和警告来帮助您记住将字符串放入资源文件中。
- 在
<Button>
代码的android:text
属性中,点击一次“Roll”字符串。 - 按
Alt+Enter
(在 macOS 上为Option+Enter
),然后从弹出式菜单中选择 Extract string resource。 - 输入
roll_label
作为资源名称。 - 点击确定。在
res/values/string.xml
文件中创建字符串资源,并将 Button 元素中的字符串替换为对该资源的引用:android:text="@string/roll_label"
- 在 Project > Android 窗格中,依次展开 res > values,然后双击 strings.xml 以在
strings.xml
文件中查看字符串资源:
<resources>
<string name="app_name">DiceRoller</string>
<string name="roll_label">Roll</string>
</resources>
第 3 步:设置视图的样式和位置
您的布局现在包含一个 TextView
视图和一个 Button
视图。在此任务中,您将排列视图组中的视图,使其看起来更具吸引力。
- 点击 Design 标签页可查看布局的预览效果。目前,这两个视图并排显示在屏幕顶部。
- 点击 Text 标签页,返回到 XML 编辑器。为
LinearLayout
标记添加android:orientation
属性,并将其值设为"vertical"
。<LinearLayout>
元素现在应如下所示:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".MainActivity">
LinearLayout
视图组会将其包含的视图按顺序排列在一行中(水平排列)或一叠中(垂直排列)。默认值为水平。由于您希望 TextView
堆叠在 Button
之上,因此您将方向设置为垂直。现在,设计如下所示,按钮位于文字下方:
- 为
TextView
和Button
添加android:layout_gravity
属性,并将其值设为"center_horizontal"
。这会使两个视图沿水平轴的中心对齐。TextView 和 Button 元素现在应如下所示:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Hello World!" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/roll_label" />
- 向线性布局添加
android:layout_gravity
属性,并为其赋予值"center_vertical"
。您的LinearLayout
元素现在应如下所示:
<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="wrap_content"
android:orientation="vertical"
android:layout_gravity="center_vertical"
tools:context=".MainActivity">
- 如需增大文本视图中的文字大小,请向
<TextView>
元素添加android:textSize
属性,并将该属性的值设为"30sp"
。sp 缩写代表可缩放像素,这是一种用于调整文字大小的度量单位,与设备的显示质量无关。TextView 元素现在应如下所示:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="30sp"
android:text="Hello World!" />
- 编译并运行您的应用。
现在,文字和按钮都放置得很好,并且文字视图中的文字更大。该按钮目前没有任何功能,因此点击它不会发生任何事情。您接下来会处理该问题。
第 4 步:在代码中获取对按钮的引用
MainActivity
中的 Kotlin 代码负责定义应用的互动部分,例如点按按钮时会发生什么。如需编写在点击按钮时执行的函数,您需要在 MainActivity 中获取对已扩充布局中 Button 对象的引用。如需获取对按钮的引用,请执行以下操作:
- 在 XML 文件中为
Button
分配 ID。 - 在代码中使用
findViewById()
方法可获取对具有特定 ID 的View
的引用。
获得对 Button
视图的引用后,您可以在应用运行时调用该视图的方法来动态更改它。例如,您可以添加一个点击处理程序,以便在用户点按按钮时执行代码。
- 打开
activity_main.xml
布局文件(如果尚未打开),然后点击 Text 标签页。 - 向按钮添加
android:id
属性,并为其指定一个名称(在本例中为“@+id/roll_button"
”)。现在,您的<Button>
元素如下所示:
<Button
android:id="@+id/roll_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/roll_label" />
在 XML 布局文件中为视图创建 ID 时,Android Studio 会在生成的 R
类中创建一个具有该 ID 名称的整数常量。因此,如果您将视图命名为 roll_button
,Android Studio 会在 R
类中生成并创建一个名为 roll_button
的整数常量。ID 名称的 "@+id"
前缀会告知编译器将该 ID 常量添加到 R 类。XML 文件中的所有视图 ID 都必须带有此前缀。
- 打开
MainActivity
Kotlin 文件。在onCreate()
内的setContentView()
之后,添加以下行:
val rollButton: Button = findViewById(R.id.roll_button)
使用 findViewById()
方法获取您在 XML 类中定义的视图的 View
引用。在这种情况下,您将从 R
类获取 Button
引用和 ID roll_button
,并将该引用分配给 rollButton
变量。
- 请注意,Android Studio 会以红色突出显示
Button
类并为其添加下划线,以表明它是一个未解析的引用,您需要先导入此类,然后才能使用它。系统可能还会显示一个提示,其中包含完全限定的类名称: - 按
Alt+Enter
(在 Mac 上,按Option+Enter
),接受完全限定类名。
第 5 步:添加点击处理程序以显示 Toast
点击处理程序是一种方法,每当用户点击或点按可点击的界面元素(例如按钮)时,系统都会调用该方法。如需创建点击处理程序,您需要:
- 执行某种操作的方法。
setOnClickHandler()
方法,用于将Button
连接到处理程序方法。
在此任务中,您将创建一个点击处理程序方法来显示 Toast
。(消息框是指在屏幕上短暂弹出的消息。)将点击处理程序方法连接到 Button
。
- 在
MainActivity
类中的onCreate()
之后,创建一个名为rollDice()
的私有函数。
private fun rollDice() {
}
- 将以下这行代码添加到
rollDice()
方法,以便在调用rollDice()
时显示Toast
:
Toast.makeText(this, "button clicked",
Toast.LENGTH_SHORT).show()
如需创建 Toast,请调用 Toast.makeText()
方法。此方法需要三个方面:
- 一个
Context
对象。借助Context
对象,您可以与 Android OS 通信并获取有关其当前状态的信息。您需要在此处添加Context
,以便Toast
对象可以告知操作系统显示 Toast。由于AppCompatActivity
是Context
的子类,因此您只需使用关键字this
即可获取相应上下文。 - 要显示的消息,此处为
"button clicked"
。 - 显示消息的时长。末尾的
show()
方法会显示 Toast。
- 在
onCreate()
中,在对findViewById()
的调用后,添加以下行以将rollDice()
分配为rollButton
对象的点击处理程序:
rollButton.setOnClickListener { rollDice() }
MainActivity
类的完整定义现在应如下所示:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rollButton: Button = findViewById(R.id.roll_button)
rollButton.setOnClickListener { rollDice() }
}
private fun rollDice() {
Toast.makeText(this, "button clicked",
Toast.LENGTH_SHORT).show()
}
}
- 编译并运行您的应用。每次点按按钮时,都应显示一个 Toast。
在此任务中,您将修改 rollDice()
方法以更改 TextView
中的文本。在第一步中,您将该文本从 "Hello World!"
更改为字符串 "Dice Rolled!"
。在第二步中,您显示一个介于 1 到 6 之间的随机数。
第 1 步:显示字符串
- 打开
activity_main.xml
,然后向TextView
添加 ID。
android:id="@+id/result_text"
- 打开
MainActivity
。在rollDice()
方法中,注释掉用于显示Toast
的代码行。 - 使用
findViewById()
方法按 ID 获取对TextView
的引用。将引用分配给resultText
变量。
val resultText: TextView = findViewById(R.id.result_text)
- 为
resultText.text
属性分配新字符串以更改显示的文本。您可以忽略将该字符串提取到资源中的提示;这只是一个临时字符串。
resultText.text = "Dice Rolled!"
- 编译并运行应用。请注意,现在点按 Roll 按钮会更新
TextView
。
第 2 步:显示随机数
最后,在此任务中,您将为按钮点击添加随机性,以模拟掷骰子。每次点击或点按该按钮时,您的代码都会从 1 到 6 中随机选择一个数字,并更新 TextView
。生成随机数的任务并非 Android 特有的,您可以使用 Random
类来完成此任务。
- 在
rollDice()
方法的顶部,使用Random.nextInt()
方法获取介于 1 到 6 之间的随机数:
val randomInt = Random().nextInt(6) + 1
- 将
text
属性设置为随机整数的值(以字符串形式):
resultText.text = randomInt.toString()
- 编译并运行应用。每次点按 Roll 按钮时,文本视图中的数字都会发生变化。
Android Studio 项目:DiceRoller
挑战:向应用添加第二个按钮,该按钮标记为“Count Up”,显示在 Roll 按钮的正下方。点按 Count Up 按钮时,该按钮应获取结果文本视图的当前值,将该值加 1,然后更新文本视图。请务必处理以下边缘情况:
- 如果结果文本视图尚不包含数字(即,如果文本视图仍具有默认的“Hello World”字符串),请将结果文本设置为 1。
- 如果该数字已为 6,则无需执行任何操作。
编码挑战解决方案代码
Android Studio 项目:DiceRoller-challenge
活动
MainActivity
是AppCompatActivity
的子类,而AppCompatActivity
又是Activity
的子类。Activity
是一个核心 Android 类,负责绘制 Android 应用界面和接收输入事件。- 所有 activity 都有关联的布局文件,该文件是应用资源中的 XML 文件。布局文件以 activity 命名,例如
activity_main.xml
。 MainActivity
中的setContentView()
方法将布局与 activity 相关联,并在创建 activity 时扩充该布局。- 布局扩充是指将 XML 布局文件中定义的视图转换为(或“扩充为”)内存中的 Kotlin 视图对象的过程。布局膨胀后,
Activity
可以将这些对象绘制到屏幕上并动态修改它们。
视图
- 应用布局中的所有界面元素都是
View
类的子类,称为视图。TextView
和Button
是视图的示例。 View
元素可以分组到ViewGroup
中。视图组充当其中视图或其他视图组的容器。LinearLayout
是一个以线性方式排列视图的视图组示例。
查看属性
android:layout_width
和android:layout_height
属性用于指示视图的权重和高度。match_parent
值会将视图拉伸到其父级的宽度或高度。wrap_content
值会将视图缩小到适合视图内容的大小。android:text
属性用于指示视图应显示的文本(如果该视图显示文本)。对于按钮,android:text
是按钮标签。LinearLayout
视图组中的android:orientation
属性用于排列其包含的视图元素。值为horizontal
时,视图从左到右排列。值为vertical
时,视图会从上到下排列。android:layout_gravity
属性用于确定视图及其所有子视图的放置位置。android:textSize
属性用于定义文本视图中文字的大小。文字大小以 sp 单位(可缩放像素)指定。通过使用 sp 单位,您可以独立于设备的显示质量来调整文字大小。
字符串
- 最佳实践是使用字符串资源,而不是在布局中硬编码字符串。
- 字符串资源包含在
values/res/string.xml
文件中。 - 如需提取字符串,请使用
Alt+Enter
(在 Mac 上,使用Option+Enter
)。从弹出式菜单中选择 Extract string resources。
使用视图
- 如需将 Kotlin 代码连接到布局中定义的视图,您需要在视图扩充后获取对视图对象的引用。在布局中为视图分配一个 ID (
android:id
),然后使用findViewById()
方法获取关联的视图对象。 - 在 XML 布局文件中为视图创建 ID 时,Android Studio 会在生成的
R
类中创建一个具有该 ID 名称的整数常量。然后,您可以在findViewById()
方法中使用该R.id
引用。 - 您可以在 Kotlin 代码中直接通过属性名称设置视图对象的属性。例如,文本视图中的文本由 XML 中的
android:text
属性定义,而在 Kotlin 中则由text
属性定义。 - 点击处理程序是一种在用户点击或点按界面元素时调用的方法。如需将点击处理方法附加到视图(例如按钮),请使用
setOnClickListener()
方法。
使用 Toast
消息框是一种视图,可在小型弹出式窗口中向用户显示简单消息。
如需创建 Toast,请对 Toast
类调用 makeText()
工厂方法,并传入三个实参:
- 应用
Activity
的上下文 - 要显示的消息,例如字符串资源
- 时长,例如
Toast.LENGTH_SHORT
如需显示消息框,请调用 show()
。
Udacity 课程:
Android 开发者文档:
其他:
此部分列出了在由讲师主导的课程中,学生学习此 Codelab 后可能需要完成的家庭作业。讲师自行决定是否执行以下操作:
- 根据需要布置作业。
- 告知学生如何提交家庭作业。
- 给家庭作业评分。
讲师可以酌情采纳这些建议,并且可以自由布置自己认为合适的任何其他家庭作业。
如果您是在自学此 Codelab,可随时通过这些家庭作业来检测您的知识掌握情况。
更改应用
打开 DiceRoller 应用。向该应用添加一个标签为“重置”的按钮,该按钮显示在 Roll 按钮的正下方。让该按钮将结果文本视图重置为 0。
回答以下问题
问题 1
Activity
上的哪种方法可膨胀应用的布局,并使其视图作为对象可用?
onCreate()
setClickListener()
setContentView()
show()
问题 2
您会使用哪个视图属性来设置视图的宽度,以便它进行调整来适应内容?
android:view_width="wrap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="match_parent"
提交应用以进行评分
检查以确保应用具有以下内容:
- 应用布局应包含一个文本视图和两个按钮。
- 应用的代码应设置两个点击处理程序,每个按钮对应一个。
- 用于重置文本视图的点击处理程序应将文本属性设置为 0。
开始学习下一课:
如需本课程中其他 Codelab 的链接,请参阅“Android Kotlin 基础知识”Codelab 着陆页。