Android UI 布局和控件






4.96/5 (98投票s)
为您的Android应用增添光彩。
- 下载 AndroidUIs.zip - 3.7 MB
- 下载 app-release-apk.zip - 456.5 KB
- 下载 sample_photos.zip - 384.9 KB
- 下载 android_icons.zip - 6.3 KB
![]() |
引言
在创建一个简单的Hello World Android项目时,您已经亲自动手了。您应该对Android应用的构建方式有了一个大致的了解。在接下来的教程中,我们将仔细研究和探索构成Android应用的各种构建块。那么,我们从何开始呢?答案就在您的Android手机上。
拿出您的Android手机,选择一个应用并启动它,您看到了什么?是用户界面!用户界面(UI)是用户能看到并与您的应用互动的一切。如今,典型的UI是基于图形的,包含各种UI控件,如文本框、按钮、复选框、单选按钮、日期选择器等等,并以各种布局呈现。自然,我们将从UI开始。
我将本文的范围设定为涵盖更常见和更重要的UI布局和UI控件,如下所示:
-
UI 布局
-
UI 控件
组织有序,一目了然
每个 Android 的用户界面都由 View 和 ViewGroup 对象的层次结构集合组成。
View 类是所有图形 UI 对象的基类,这些对象统称为UI 控件或Widgets,例如您在 Android 设备屏幕上看到的Button、TextView、EditText、CheckBox、RadioButton、ImageView、Spinner等等。每个可见的 UI 控件都占用屏幕上的一块区域,并通过点击、触摸和按键等事件提供您与应用之间的交互点。您可以将各种View对象比作房子里的家具和电器等家居用品。
另一方面,ViewGroup 类是不可见的组织者,它提供各种UI 布局来定位屏幕上的各种View对象。例如,您可以使用LinearLayout布局以线性方式将 UI 控件一个接一个地排列,或者使用RelativeLayout布局将它们彼此相对定位。事实上,ViewGroup 类也派生自View 类,换句话说,您可以将一个ViewGroup 对象(子)嵌套在另一个ViewGroup 对象(父)中,并且每个都可以采用不同的布局。您可以将ViewGroup的布局比作房子里房间和空间的布局。
图 1 到图 3 的三张图最好地说明了这一概念。
首先是概念规划。图 1 中的概念化 UI 由许多View对象组成,这些对象被组织成两个ViewGroups——一个ViewGroup嵌套在另一个中。这就像房子的内部平面图,一个空间嵌套在另一个空间中,每个空间都可以以不同的方式布置自己的家居用品。
![]() |
图1:抽象形式的用户界面
|
为了实现该计划,我们决定整体UI布局应为RelativeLayout,嵌套布局为LinearLayout。我们还决定了在各自布局中为每个View对象使用的实际UI控件,如TextView,EditText,CheckBox等。最终的具体计划如图2所示。这就像决定了每种家具和电器的类型及其在每个空间中的位置。
![]() |
图2:具体形式的用户界面
|
当计划实施后,您可以在 Android 虚拟设备(AVD)上看到 UI,如图 3 所示。
![]() |
图3:实现中的用户界面
|
亲自动手
您已经了解到,任何 Android UI 的基本构建块都包含 View 对象和 ViewGroup 对象。它们协同工作,为用户提供 Android 应用的外观、感受和交互。由于 UI 是用户看到和与您的应用交互的唯一事物,因此每个新的 Android 应用开发者首先必须学习的就是构建 UI。您也不例外。有什么比亲自动手构建 Android UI 更好的学习方式呢。
您需要一个 AVD 或物理设备来测试您的应用。我使用了基于 Nexus 4 的 AVD 配置,如图 4 所示。特别注意取消选中键盘选项,以便 AVD 中可以使用软键盘。建议您使用相同的 AVD 配置,以便我们大部分时间都能保持一致。您可以参考我的文章 设置您的 Android 开发环境 来了解如何创建 AVD。
![]() |
图4:AVD配置
|
所以,卷起袖子,我们开始吧……
准备工作
启动您的Android Studio。如果它打开了一个现有项目,您应该首先通过选择菜单栏中的文件 > 关闭项目来关闭它,这将关闭现有项目并将您带到欢迎界面。当您在欢迎界面时,点击新建项目...,然后按照图5到图9的截图来设置并启动一个名为"AndroidUIs"的新Android项目,其中包含一个名为"MainActivity"的空白Activity模板。
![]() |
图5:配置新项目
|
![]() |
图6:选择表单因子
|
![]() |
图7:添加一个Activity
|
![]() |
图8:选择选项
|
Android将创建一个新项目,其中包含一个名为“MainActivity”的默认Activity和一个名为“activity_main.xml”的默认布局(图9)。
![]() |
图9:新项目启动
|
LinearLayout
我们将以一个名为 LinearLayout 的 GridView 布局开启 Android UI 构建的学习之旅。
打开“activity_main.xml”,这是 MainActivity UI 的布局文件,认真按照以下步骤操作,您将在此过程中学到宝贵的知识点:
-
切换到文本视图(图9的左下角),然后将默认的RelativeLayout更改为LinearLayout,并从XML页面删除默认的TextView块。
-
切换到 设计 视图,您现在应该看到 LinearLayout 布局出现在 组件树 窗格的 设备屏幕 节点下。突出显示此 LinearLayout 节点,然后在 组件树 窗格下方的 属性 窗格中找到 orientation 属性,点击并将其设置为 horizontal。
-
从Widgets调色板中拖放一个Button控件到虚拟设备的屏幕上。Button控件也出现在组件树窗格的设备屏幕节点下。(图12)
图12:拖放一个Button控件 -
继续从“Widgets”调色板中向虚拟设备屏幕上添加一个Button控件。这两个按钮将水平并排放置(图13)。
图13:带有两个Button控件的LinearLayout学习要点1每个UI组件的状态(颜色、大小、边距、内边距、权重等)都可以通过其属性进行更改。当您点击某个UI组件时,可以在Android Studio的属性窗格(右下角)中看到与该特定UI组件相关的所有属性。这使得Android Studio成为学习各种UI组件的绝佳工具! -
background
由于 LinearLayout 不可见,我们将其 background 属性更改为新颜色,如图 14 所示。(确保您已在 组件树 中选中 LinearLayout (Horizontal)。)您会看到整个屏幕都被渲染为新颜色,换句话说,LinearLayout 覆盖了整个屏幕。为什么会这样?答案在于 LinearLayout 的 layout:width 和 layout:height 属性。它们都取值“match_parent”,这意味着“与父屏幕一样大”。
图14:更改背景到目前为止,您仅仅通过在“设计”视图中拖放就创建了初始UI。您不好奇幕后发生了什么吗?Android Studio已将您在“设计”视图中完成的所有操作转换为一个XML文件,即“activity_main.xml”。切换到文本视图,您将看到如图15所示的XML代码。
图15:activity_main.xml请注意
节点中与“设计”视图中“属性”窗格中的相应属性对应的以下属性。 android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffb9d7ff"
重力
-
保持LinearLayout (Horizontal)选中状态,展开gravity属性,分别勾选right和center值。这将使两个按钮定位在整个屏幕的右中位置。尝试其他复选框值(单独或组合)以查看效果。
图16:玩转重力学习要点2LinearLayout 的 gravity 属性用于确定其子 Views 的定位。它可以取一个或多个常量值(如图 15 所示),用“|”分隔,例如“center|right”。以下代码已作为属性添加到
节点中,位于"activity_main.xml"。切换到Text视图查找它。 android:gravity="center|right"
完成“重力”属性的调整后,撤消所有更改,将屏幕恢复到图14所示的状态。
-
填充
回到图 14 中的屏幕,保持 LinearLayout (Horizontal) 选中状态,展开 padding 属性,并分别在 left 和 top 参数中输入 50dp 和 70dp。这将使两个按钮向右和向下移动规定的量,如图 16 所示。尝试使用不同值(单独或组合)的其他参数以查看效果。
图17:玩转填充学习要点3LinearLayout 的 padding 属性用于指定其边框与其最近的子 Views 之间的内部空间。您可以独立指定布局的左、上、右和下侧的内边距。以下代码已作为属性添加到“activity_main.xml”中的
节点中。切换到“文本”视图并查找它们。 android:paddingLeft="50dp" android:paddingTop="70dp"
完成“填充”属性的调整后,撤消所有更改,将屏幕恢复到图14所示的状态。
-
布局:宽度,布局:高度
回到图 13 中的屏幕,保持 LinearLayout (Horizontal) 选中状态,在 Properties 窗格中查找 layout:width 和 layout:height 属性,将其值更改为“wrap_content”。您看到了什么?LinearLayout 已调整为刚好适应两个按钮,如图 18 所示。图18:刚好合适学习要点4LinearLayout 的 layout:width 和 layout:height 属性允许您设置布局的宽度和高度。您可以使用 dp(密度独立像素)指定精确的宽度和高度,但通常情况下,您会使用以下常量之一来设置宽度或高度,即“fill_parent”、“match_parent”或“wrap_content”。请注意,fill_parent 从 API Level 8 开始已弃用,并被 match_parent 取代。match_parent 常量会将布局拉伸以完全适应其父 GridView(如果有内边距,则减去内边距),例如屏幕,而 wrap_content 将调整布局大小以适应其所有子 Views。
"activity_main.xml" 中
节点内的 android:layout_width 和 android:layout_height 属性应已修改,如图所示。切换到 Text 视图并查找它们。 android:layout_width="wrap_content" android:layout_height="wrap_content"
完成后,撤消所有更改,将屏幕恢复到图14所示的状态。
-
方向
回到图 14 中的屏幕,保持 LinearLayout (Horizontal) 选中状态,在 Properties 窗格中查找 orientation 属性,将其值更改为“vertical”。您看到了什么?这两个按钮现在将垂直堆叠。您还会注意到 组件树 窗格中的 LinearLayout (Horizontal) 已更改为 LinearLayout (Vertical)(图 19)。图19:垂直方向学习要点5orientation 属性是 LinearLayout 独有的,使其有别于其他 GridView 布局。它取值为“horizontal”或“vertical”。它控制子 View 在 LinearLayout 中的排列方式。水平方向会将它们排列成一排多列,而垂直方向会排列成一列多行。默认方向为“horizontal”。“activity_main.xml”中“
”节点中的“android:orientation”属性应已修改,如图所示。切换到“文本”视图并查找它。 android:orientation="vertical"
-
边距
切换到“文本”视图,然后添加一行代码,如图20所示。
图20:垂直方向在您输入时,Android Studio 将提供一个建议词下拉列表,以帮助您自动完成代码,如图 21 和 22 所示。(为了让 Android Studio 帮助您,请尝试输入慢一些;当匹配的词出现时,使用方向键导航到它,然后按 Tab 键选择它。)
图21:垂直方向图22:垂直方向这行代码的效果如图23所示。
图23:垂直方向您刚刚在 LinearLayout 周围的边框外部添加了 16dp 的边距,其值引用于“dimens.xml”中的“activity_vertical_margin”元素,如图 24 所示。要在 XML 中引用任何资源,语法如下:
@resourceType/resourceName
.图24:dimens.xml学习要点6“android:layout_margin”属性设置布局的整体边距,即当前Views(例如布局)的边框与最近的外部Views之间的外部空间。您还可以分别指定底部、左侧、右侧和顶部的单独边距,如图25所示。图25:layout_margin的变体
摘要LinearLayout 是一个 ViewGroup 对象,它按照其独特的属性 orientation 的指示,将所有子 Views 逐个排列成水平或垂直方向。LinearLayout 的所有子 Views 始终线性地一个接一个地放置。水平方向会将它们排列成一排多列,而垂直方向则排列成一列多行。默认方向是“horizontal”。
LinearLayout 是 GridView 对象中最简单直接的布局模型。但它的灵活性最差,因为它只允许水平或垂直布局。虽然可以使用嵌套的 LinearLayouts(即一个 LinearLayouts 在另一个 LinearLayouts 中)实现附加布局,但这不是明智之举,因为这会使您的设计复杂化并降低性能。如果您发现自己使用了多个嵌套的 LinearLayouts,那么是时候考虑一个单一的 RelativeLayout 了。
RelativeLayout
在当前项目中,创建一个名为“RelativeLayout”的新 Activity,以练习另一个 GridView 对象 - RelativeLayout。
-
按照图26到图27所示的步骤创建新的Activity。
图26:新建空白活动图27:设置新活动 -
空白 Activity 模板创建的 "activity_relative_layout.xml" 文件带有一个 RelativeLayout 和一个显示“Hello world!”的 TextView。(图 28)
图28:拖放布局 -
在“设计”视图中,从“Widgets Palette”中拖放一个“Button”控件(图29和30)。当您在屏幕上拖动时,会出现一个对话框,向您更新有关到
右侧和下方的 边距信息(图29)。指的是“Hello world!”的TextView控件。换句话说,它向您展示了“Button”控件相对于“TextView”控件的相对位置。 图29:拖动一个Button控件图30:放置一个Button控件 -
在“文本”视图中查看“activity_relative_layout.xml”(图31)。
图31:带有一个按钮控件的LinearLayout您会注意到TextView已被分配了一个新的android:id属性,如下所示
android:id="@+id/textView2"
新的 <Button> 节点具有以下属性,通过其 android:id 属性引用了“Hello world!” TextView。这些属性决定了此按钮相对于 TextView 的位置。
android:layout_below="@+id/textView2" android:layout_toRightOf="@+id/textView2" android:layout_toEndOf="@+id/textView2"
实际距离由以下边距决定
android:layout_marginLeft="23dp" android:layout_marginTop="48dp"
-
在“设计”视图中,从“Widgets Palette”中拖放第二个“Button”控件(图32和33)到屏幕的右下角。当按钮接近屏幕边缘时,会出现一个对话框,向您更新与父级ViewGroup(即RelativeLayout)右侧和底部对齐的相应边距信息(图32)。
图32:拖动第二个Button控件图33:放置第二个Button控件 -
在“文本”视图中查看“activity_relative_layout.xml”(图34)。
图34:带有两个按钮控件的LinearLayout您会注意到已添加了第二个节点。请注意这些属性,它们决定了此第二个按钮相对于其父GridView(即RelativeLayout)的位置。
android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true"
实际距离由以下边距决定
android:layout_marginRight="68dp" android:layout_marginBottom="130dp"
摘要在 RelativeLayout 模型中,其子 Views 的定位通过以下任一方式指定:
相对于其同级 Views,使用这些属性:android:layout_above、android:layout_below、android:layout_toRightof、android:layout_toLeftof、android:layout_toStartof 和 android:layout_toEndof,它们取其同级 id 的值,语法如下:
android:layout_below="@+id/viewName"例如,
android:layout_below="@+id/textView2"相对于其父 GridView,使用这些属性:android:layout_alignParentBottom、android:layout_alignParentTop、android:layout_alignParentLeft、android:layout_alignParentRight、android:layout_alignParentEnd 和 android:layout_alignParentStart,其值为 true 或 false。
尽管 RelativeLayout 模型为 UI 上的 View 对象布局提供了最大的灵活性,但它需要更多时间进行规划和设计。对于只需要 2D 结构的 UI 布局,请使用 TableLayout。
TableLayout
在当前项目中,创建一个名为“TableLayout”的新 Activity,以练习另一个 GridView 对象 - TableLayout。请按照以下步骤操作:
-
在“设计”视图中打开“activity_table_layout.xml”,然后删除组件树窗格中的默认RelativeLayout和TextView。
-
从布局调色板中拖放一个TableLayout布局到虚拟设备的屏幕上。
-
将一个大文本控件(实际上是一个TextView视图)拖放到虚拟设备的屏幕上(图35)。当您将其拖过屏幕时,会出现一个二维网格,并弹出一个对话框,显示当前位置的行和列索引号。(索引号从零开始。)将TextView放到(第1行,第1列)(图36)。
图35:拖动一个大文本图36:添加了一个大文本 -
让我们将默认文本更改为其他内容,例如“登录”。按照图 37 中的步骤操作。双击 TextView 以弹出对话框。在对话框中,点击“文本:”文本框旁边的“...”按钮以弹出资源窗口,然后点击此窗口左下角的新建资源按钮并选择新建字符串值...。
图37:添加新资源一个新窗口打开,供您创建新的字符串资源,根据需要输入以下值,然后点击 OK(图 38)。
图38:输入新资源值新的字符串资源已添加到“strings.xml”。请查看。(图39)。
图39:新资源已添加到strings.xml如果您查看“activity_table_layout.xml”文件(图 40),TextView 的 android:text 属性现在通过语法 @string/sign_in 指向新的字符串资源。
图40:TextView指向新的字符串资源其结果如图41所示。
图41:TextView显示新值学习要点7当您需要新的文本字符串时,不要硬编码。相反,您应该创建一个新的字符串资源,将该文本字符串作为值。然后,您可以在 XML 或代码中引用此字符串资源,只要您需要在任何 UI 上使用文本字符串。这是可重用性和可维护性的最佳实践。您应该始终参考图 37 至 41。 -
您将继续自行构建 TableLayout UI。完成的 UI 应如图 42 所示。除了用于“登录...”标签的 Large Text 小部件,
-
拖放两个中等文本小部件到UI上,并分别将其text属性更改为“Email”和“Password”。(按照图37到40的步骤操作。)
-
将一个电子邮件和密码文本字段(实际上是EditText视图)拖放到UI上,并将“电子邮件”和“密码”字样插入到它们各自的提示属性中。您应该使用您上面创建的两个字符串资源。如何操作?在“属性”窗格中,点击“提示”属性旁边的文本字段,会出现一个标有“...”的按钮,然后点击它以弹出资源窗口(类似于您在图37中看到的)。这次,您应该看到您上面为“电子邮件”和“密码”创建的两个字符串被列出,直接使用它们即可。这就是可重用性的魅力!
注意设置后,当文本字段为空时,hint属性的值将显示在EditText文本字段中。
-
最后,拖动一个 Button 小部件到 UI 上,并将其 text 属性更改为“让我进入!”。
图42:一个TableLayout UI图 44 中的 2D 网格应该可以帮助您可视化 TableLayout 中各种 View 控件的定位(图 43)。
图43:带网格的TableLayout UI为了了解 TableLayout 如何组织子 View,让我们研究一下 "activity_table_layout.xml" 中的这段代码片段(图 44)。
图44:activity_table_layout.xml片段 -
学习要点8TableLayout 中的每一行都作为一个节点追加,其中包含子 Views。 节点的顺序很重要。当引用此 XML 时,将从上到下遍历 节点,以确定哪个在上方,哪个在下方。换句话说,XML 文件中 节点的顺序将直接转换为其在 TableLayout 中的行索引,即文件中第一个将显示为 TableLayout 中的第一行,第二个为第二行,依此类推。另一方面,子 View 在特定行中的位置由 android:layout_column 属性指示 android:layout_column="an integer indicating a zero-based column index"例如,android:layout_column="1"表示行中的第二列。
此外,子视图可以使用 android:layout_span 属性占据多于一列。最终,TableLayout 的总列数由列数最多的行决定。
FrameLayout, ImageView
FrameLayout 是一个 ViewGroup,它将屏幕划分为多个区域块,每个区域块都应该容纳一个子 View。您可以在一个块中放置多个子 View,然后后面的子 View 将覆盖前面的子 View。子 View 的 android:layout_gravity 属性将决定它将进入哪个块。让我们使用 FrameLayout 作为布局模型构建一个页面,该页面包含一个 ImageView,上面覆盖一个 TextView。
-
创建一个名为“FrameLayout”的新Activity,然后按照以下步骤创建一个如图45所示的UI。
- 在“设计”视图中打开其布局XML文件“activity_frame_layout.xml”
- 删除默认的RelativeLayout和TextView
- 从调色板中将一个FrameLayout布局拖放到屏幕上
- 将一个 ImageView 拖放到屏幕中央,并将其 src 属性设置为“@drawable/ic_launcher”
- 拖放一个大文本覆盖 ImageView
图45:UI预览 -
在文本视图中打开“activity_frame_layout.xml”,XML内容应如图46所示。我必须承认,我在这里对TextView的android:text属性的文本进行了硬编码,真是罪过!但是您应该听取学习要点7中的建议。尝试更改android:layout_gravity属性的值,并观察预览屏幕中的变化。
图46:activity_frame_layout.xml -
在 AVD 上运行它,您应该会看到如图 47 所示。
图47:EditText中的文本选择
Button
到目前为止,我们已经探讨了四种 GridView 布局——LinearLayout、RelativeLayout、TableLayout 和 FrameLayout。您是不是迫不及待地想品尝您的劳动成果了?您的愿望得到了满足。但是,如果没有 Button 控件的帮助,这无法实现。因此,我们暂时偏离布局模型,转而研究各种 UI 控件。第一站,当然是 Button。
Button 控件在用户界面上提供一个区域,用户可以触摸该区域以启动一个动作。您将在“MainActivity”上创建多个按钮,以便我们可以导航到您迄今为止创建的各种布局页面。
让我们重新审视图 22 中的“activity_main.xml”。
-
weight
在“文本”视图中打开“activity_main.xml”,然后将以下代码分别添加到第一个和第二个Button节点。
android:layout_weight="1.0"
和
android:layout_weight="2.0"
最终代码应如图 48 所示,屏幕如图 49 所示。
图48:android:layout_weight图49:结果发生了什么?第一个按钮被赋予了其父级 GridView 的三分之一,而第二个按钮被赋予了剩余的三分之二。这是由于分别将 1.0 和 2.0 的值分配给了相应按钮的 android:layout_weight。这些值是相对的,表示它们将占用的 GridView 的比例。通过将值更改为 1.2 和 2.4 也可以实现相同的效果。试试看!
学习要点9android:layout_weight 属性设置了 View 在 LinearLayout 中相对于其他 View 所占用的宽度或高度(取决于方向)的比例。它会影响水平方向 View 的宽度和垂直方向 View 的高度。 -
从两个按钮中移除android:android_weight属性,再添加四个Button控件,将所有五个按钮的android:layout_width属性设置为“match_parent”,并将其android:text属性更改为一些新创建的字符串资源。最终的UI应如图50所示。(您以前已经做过所有这些,所以就当作复习吧。;P)
图50:新外观修改后的*activity_main.xml*应如图51所示。
图51:修改后的activity_main.xml -
图标标题
Button 控件更常见的是以文本标题渲染,但也可以以图标或两者兼有渲染。在“文本”视图中打开“activity_main.xml”,按照图 52 到 54 的步骤在 LinearLayout 按钮的文本标题上方添加一个图标。我们将使用 Android Studio 提供的默认图标“ic_launcher”。
图51:向按钮添加可绘制对象图53:向按钮添加可绘制对象图54:向按钮添加可绘制对象瞧,ic_launcher 图标已添加到 LinearLayout 按钮的顶部(图 55)。
图55:已向按钮添加可绘制对象 -
按钮事件
现在我们将为 RelativeLayout 按钮添加交互性,以便当用户触摸它时,应显示 RelativeLayout 页面(图 33)。我们来做一下:
-
在文本视图中打开 *activity_main.xml*,将 Android:onClick 属性添加到渲染 RelativeLayout 按钮的 节点,并为其分配将处理触摸事件的方法(事件处理程序)名称。我将其命名为“getRelativeLayoutPage”。 (图 56)
图56:添加Android:onClick -
打开托管“activity_main.xml”布局的Activity,即*MainActivity.java*。onCreate方法内的setContentView方法将“activity_main.xml”布局绑定到*MainActivity.java*。在代码中添加一个名为“getRelativeLayoutPage”的方法,如图56所示。如果它提示错误,这是因为View类包含在尚未导入的android.view.View包中。别担心!只需点击它一次,然后按Alt + Enter,这个问题就会立即消失。感谢Android Studio。
图57:添加事件处理程序 -
将高亮显示的代码添加到 getRelativeLayoutPage 方法中(图 58)。如果它提示另一个错误,这是因为 Intent 类包含在尚未包含的 android.content.Intent 包中。您这次应该知道如何解决它了。
图58:向按钮添加可绘制对象一个 Intent 对象是 Android 描述消息的方式,说明其“意图”做某事,即导航到 RelativeLayout。然后将此 Intent 对象传递给 startActivity 方法以执行预期操作。
-
在 AVD 或物理 Android 设备上启动您的应用,它应该会从 MainActivity 页面开始,触摸 RelativeLayout 按钮应该会将您带到 RelativeLayout 页面。做得好!您将对 TableLayout 和 FrameLayout 按钮执行相同的操作。您完成的应用应该如图 58 所示运行。
图59:按钮动作!
-
-
自定义样式
我们可以自定义按钮控件的背景,以表示按钮的三种状态 - 按下、聚焦和默认(既未按下也未聚焦)。让我们来做一下:
-
将“android_icons.zip”下载到您的计算机并解压缩,得到三张图片,分别是“ic_action_search”、“ic_action_send”和“ic_action_refresh”。(这些图片是Android Developers 的 Action Bar Icon Pack 的一部分。)按照图 60 到 63 的步骤将这些图片导入到可绘制资源文件夹中。
图60:添加新图像资产图61:导入图像图62:导入图像图63:导入图像 -
在 res 目录下创建一个名为“drawable”的子目录(图 64 和 65)。
图64:创建一个drawable目录图65:创建一个drawable目录 -
在 drawable 目录中添加一个名为“button_custom”的可绘制资源文件(图 66 和 67)。
图66:添加可绘制资源文件图67:添加可绘制资源文件新创建的可绘制资源文件将保存为 *button_custom.xml*。您的可绘制对象现在应该包含如图 68 所示的这些资源。
图68:所有可绘制资源 -
打开 *button_custom.xml* 并添加以下代码,如图 69 所示。
图69:button_custom.xml“button_custom.xml”将这三张图片绑定到各自的状态——按下、聚焦和默认(既未按下也未聚焦)。
注意- 元素的顺序很重要。当引用此drawable时,将从上到下遍历
- 元素,以确定哪个适用于当前按钮状态。默认drawable必须放在最后,因为它仅在android:state_pressed和android:state_focused都被评估为false时才适用。
-
打开 *activity_relative_layout.xml*,在第一个按钮的 节点中,删除 android:text 属性,然后添加如图 69 所示的高亮代码。“button_custom.xml”现在已应用于第一个按钮控件的背景。
图70:向按钮添加可绘制对象 -
在AVD或物理Android设备上启动您的应用,导航到RelativeLayout页面。第一个按钮的背景现在应该显示为
。触摸它会使其变为
。当按钮获得焦点时,其背景将变为
。(图71)
图71:自定义按钮有效!
-
TextView
顾名思义,TextView 是一个 View 对象,它只是向用户显示文本。默认情况下,它不可编辑。它通常用于显示标题、静态文本信息以及其他 View 对象的标签。
让我们重新审视“activity_table_layout.xml”,并仔细查看其中一个用于“登录...”的TextView对象。
-
在“文本”视图中打开“activity_table_layout.xml”。Android Studio 在“调色板”中将此 TextView 称为“大文本”,因为其 android:textAppearance 属性已分配文本大小“?android:attr/textAppearanceLarge”(图 72),等于 22sp。类似地,还有两个其他 TextView 被 Android Studio 称为“中等文本”和“小文本”。它们的 android:textAppearance 属性分别分配了文本大小“?android:attr/textAppearanceMedium”和“?android:attr/textAppearanceSmall”。前者的文本大小为 18sp,而后者为 14sp。
图72:TextView -
向TextView添加两行,如图72中高亮显示的部分。
图73:TextView在第一行高亮部分,您通过将 android:textIsSelectable 属性设置为“true”使 TextView 可选择,这允许用户对其内容进行选择手势,从而触发 Android 系统的复制和粘贴功能。
在第二行高亮部分,您通过将 android:textColorHighlight 设置为某个颜色值,使文本在被触摸时可以改变颜色。当它设置为“true”时
在 AVD 或实体设备上试试看!在我的 AVD 上瞥见它运行(图 74)。它奏效了!
图74:高亮、复制、粘贴
EditText
EditText 是 TextView 的扩展,它拥有丰富的编辑功能。它提供一个文本字段,允许用户输入文本。它可以是单行或多行。触摸 EditText 控件会放置光标并自动显示软键盘。除了输入之外,EditText 还配备了各种高效功能,例如允许用户选择、剪切、复制和粘贴文本、输入自动完成以及自定义键盘以适应输入类型。
仍然在“activity_table_layout.xml”中,这次我们将仔细查看其“电子邮件”的EditText对象。
-
在“文本”视图中打开“activity_table_layout.xml”。Android Studio 在“调色板”中将此 EditText 称为“电子邮件”,因为其 android:inputType 属性已分配值“textEmailAddress”(图 75)。
图75:XML中的EditText这是一种创新的方式,告诉 Android 系统它正在等待电子邮件输入。那么,这有什么大不了的呢?让我们在 AVD 上运行它,并将光标放在此电子邮件文本字段中。软键盘将如图 76 所示。
图76:电子邮件输入类型键盘保持盯着软键盘(我是认真的),同时将光标放在密码文本字段上。注意键盘上的任何变化,是的,“@”键已被逗号替换(图77)
图77:密码输入类型键盘将图 75 中的高亮行更改为:
android:inputType="number"
并在 AVD 上重新启动,这次您将获得一个基本数字键盘!(图 78)。(玩完后记得撤销您的操作。)
图78:数字键盘学习要点10我们已经看到 EditText 的 android:inputType 属性可以用来指示要输入到 Android 系统的文本类型,反过来,Android 系统会提供匹配的软键盘供使用。此目的的一些常见输入类型值为:
- “text”,这是默认值,调用普通文本键盘。
- “textEmailAddress”,它调用包含@键的普通文本键盘。
- “number”,它调用一个基本的数字键盘。
- “phone”,它调用一个电话拨号盘。
此外,android:inputType 属性还可以定义其他键盘行为,例如屏蔽密码文本、允许多行输入或将新句子首字母大写等等。其中一些输入类型是:
- “textPassword”,它调用普通文本键盘,但会屏蔽输入的文本。
- “textMultiLine”,它调用普通文本键盘,允许用户输入包含换行符的长字符串。
- “textCapSentence”调用正常文本键盘,将每个新句子的首字母大写。
- “textAutoCorrect”它调用普通文本键盘,提供帮助词来纠正常见的拼写错误。
您可以使用“|”分隔符为android:inputType属性指定多个输入类型。如下所示
android:inputType="textCapSentence|textAutoCorrect"
-
EditText 附带选择功能,可让您剪切、复制和粘贴。在 AVD 或物理设备上试一试,它运行得非常流畅!(图 79)。
图79:EditText中的文本选择
更多用户界面控件
我们已经处理了这些UI控件,即Button、ImageView、TextView和EditText。我们将继续探索更多UI控件——CheckBox、RadioButton和RadioGroup、ToggleButton、Spinner、AutoCompleteTextView、Progress Bar和Pickers。
在当前项目中,准备好这些东西:
- 创建一个名为“LinearLayout”的新Activity
- 在“设计”视图中打开其布局XML文件“activity_linear_layout.xml”
- 删除默认的RelativeLayout和TextView
- 从“调色板”中将一个 LinearLayout 布局拖放到屏幕上,并将其方向设置为“垂直”,将其 layout_width 和 layout_height 设置为“fill_parent”或“match_parent”。
CheckBox
CheckBox 允许用户选择或取消选择一个选项。当我们希望允许用户选择多个互斥选项时,我们会使用一组复选框。请按照以下步骤构建复选框列表:
-
在“设计”视图中打开“activity_linear_layout.xml”,从“调色板”中拖放一个新的LinearLayout到第一个LinearLayout上,并将其方向设置为“水平”,将其layout_height设置为“match_parent”,以便您可以在其中拖放复选框。这样,您就将一个LinearLayout嵌套在另一个LinearLayout中(图80)。您将在内部LinearLayout中构建您的复选框。
图80:嵌套的LinearLayout -
将一个 CheckBox 小部件拖放到内部 LinearLayout 上。将 CheckBox 的 text 重命名为“慢跑”。请记住,您应该创建一个字符串资源,然后引用它,而不是硬编码(81)。(记住 学习要点 7)
图81:新的字符串值资源“activity_linear_layout.xml”和UI应如图82所示。
图82:XML中的复选框 -
请注意每个
节点中的这三个属性:android:id、android:checked和android:onClick。我们将在接下来讨论它们。 -
在文本视图中打开“activity_linear_layout.xml”,将 Android Studio 默认提供的所有 android:id 值更改为更具描述性的名称。例如,不要使用“@+id/checkBox”或“@+id/checkBox2”,而应为“慢跑”复选框使用“@+id/chkJogging”,为“游泳”复选框使用“@+id/chkSwimming”,依此类推。“chk”前缀是复选框的缩写。实际上,您应该对所有元素的 ID 都这样做。
学习要点11当您在 XML 中创建一个新元素时,您必须通过 android:id 属性为其分配一个新 id,其值类似于 "@+id/"。对于新创建的元素,需要“+”号,它指示 Android 构建器在 R.java 类中创建一个具有唯一整数标识符的新静态变量。一旦创建,后续引用无需“+”号,例如“@id/ ”。 我必须强调一个重要点,您应该将 Android Studio 默认给出的所有 android:id 值更改为更具描述性的名称。例如,不要使用“@+id/checkBox”或“@+id/checkBox2”,而应为“慢跑”复选框使用“@+id/chkJogging”,为“游泳”复选框使用“@+id/chkSwimming”,依此类推。“chk”前缀是复选框的缩写。
-
android:checked 属性接受一个布尔值,可以是true或false,true表示选中,false表示未选中。您可以使用此属性来设置CheckBox的初始选中状态。
-
接下来是 Android:onClick 属性。我们已经在图 55 的 Button Event 中讨论过它。这里的 Android:onClick 已被分配了一个事件处理程序(方法),名为“onCheckboxClicked”,位于其 Activity 类,即 "LinearLayout.java"。
-
重复步骤2到6以创建更多复选框。之后,将内部LinearLayout的layout_height设置为“wrap_content”。完成的UI应如图83所示。
图83:复选框 -
您将向“LinearLayout.java”添加一个方法来处理复选框事件。(如果您遇到任何错误,请参考图55寻求帮助。)打开托管“activity_linear_layout.xml”的“LinearLayout.java”,添加“onCheckboxClicked”方法,如下所示(图84);
图84:添加事件处理程序在 Android 中,用于定位特定 View 对象(UI 元素)的 Java 代码是:
ViewType viewObj = (ViewType)findViewById(R.id.<id of="" the="" view=""><id of the View>)
例如,CheckBox chkJogging = (CheckBox) findViewById(R.id.chkJogging);
您可能会开始意识到使用描述性名称作为ID的好处(学习要点11)——您只需阅读ID就知道您指的是哪个View对象,而使用“checkbox2”或“checkbox3”这样的ID则无法做到这一点,不是吗?
那么这个方法有什么作用呢?当您选中或取消选中任何复选框时,它将通过Toast对象回显当前所有被选中的复选框的名称。但是,在您运行测试之前,它必须从“MainActivity”页面导航。让我们使用“MainActivity”页面中显示“LinearLayout”的第一个按钮来完成此操作。
-
还在等什么,你以前做过类似的练习,记得图56吗?
-
在“文本”视图中打开“activity_main.xml”。
- 将此行添加到第一个 节点
android:onClick="getLinearLayoutPage"
-
将此方法添加到“MainActivity.java”
public void getLinearLayoutPage(View view) { Intent intent = new Intent(getApplicationContext(), LinearLayout.class); startActivity(intent); }
大功告成!
-
-
现在,您可以在 AVD 或您的 Android 设备上尝试一下。它会像这样工作(图 85)。
图85:复选框在工作!
RadioButton, RadioGroup
与 CheckBox 类似,RadioButton 提供用户一个选择的选项。然而,单选按钮不是单独存在的。它属于一组单选按钮,其中一次只能选择其中一个,例如性别的选择。如何确保这一点,答案是“将它们分组到 RadioGroup 中”。这样,系统确保一次只能选择一个单选按钮。
-
在“设计”视图中打开“activity_linear_layout.xml”,从“调色板”的“容器”部分拖动一个RadioGroup并将其放置在复选框的LinearLayout下方(确保您已将此LinearLayout的layout_height设置为“wrap_content”)。在此RadioGroup的“属性”窗格中,将其方向设置为“水平”,并将其layout_height和layout_weight设置为“match_parent”,以便您可以在其中拖放单选按钮。RadioGroup是LinearLayout的子类,默认方向为垂直,但它是为了将一组单选按钮分组。接下来,将两个单选按钮拖放到RadioGroup中,分别用于“女性”和“男性”。完成后,将layout_height更改为“wrap_content”。它应如图86所示。
图86:单选按钮 -
在文本视图中打开“activity_linear_layout.xml”,将“onRadioButtonClicked”分配给Android:onClick属性。完成的单选按钮XML应如图87所示。
图87:XML中的单选按钮 -
将“onRadioButtonClicked”方法添加到“LinearLayout.java”中,如下所示(图88);
图88:单选按钮的事件处理程序 -
这就是完成后的 UI 在 AVD 中的样子(图 89)
图89:复选框在工作!
提示当您想向用户显示所有选项时,请使用 RadioButton。否则,您应该考虑使用 Spinner。
ToggleButton
ToggleButton 是一个开/关开关。它可用于打开和关闭振动模式、静音模式、WiFi 连接等功能。我们将在 LinearLayout 页面添加一个 ToggleButton 来切换 WiFi 连接。
-
在“设计”视图中打开“activity_linear_layout.xml”,从“调色板”中拖动一个ToggleButton控件并将其放置在RadioGroup下方。将其textOn和textOff属性分别设置为“WiFi On”和“WiFi Off”(图90)。
图90:ToggleButton -
在文本视图中打开“activity_linear_layout.xml”,将“onToggleClicked”分配给Android:onClick属性。完成的切换按钮XML应如图91所示。
图91:XML中的ToggleButton -
将“onToggleClicked”方法添加到“LinearLayout.java”中,如下所示(图92);
图92:ToggleButton的事件处理程序 -
在“AndroidManifest.xml”(图 93)中添加以下权限,以允许您的应用访问和更改设备的 WiFi 状态,同时防止处理器休眠或屏幕变暗。
图93:在Manifest中设置权限 -
您必须使用真实设备进行测试。这是我的设备在横向模式下的屏幕截图(图94)。
图94:ToggleButton在工作!
Spinner
Spinner 只是一个花哨的名称,指代我们非常熟悉的下拉列表。您将在您的应用中构建一个 Spinner,其中包含生肖名称列表。每当进行选择时,您的应用将回显所选生肖的名称。
- 在“strings.xml”中,添加一个名为“zodiac”的字符串数组,如图95所示。这将作为绑定到您的spinner的数据源。图95:数据源
-
在“设计”视图中打开“activity_linear_layout.xml”,从“调色板”中拖动一个Spinner控件并将其放置在ToggleButton下方(图96)。
图96:Spinner -
在“文本”视图中打开“activity_linear_layout.xml”,相应地更改android:id的默认值,如图97所示。
图97:XML中的Spinner -
在“LinearLayout.java”中,创建一个ArrayAdapter并将其附加到旋转器,如图98所示。
图98:将Spinner绑定到数据源在该方法中,一个 ArrayAdapter(Adapter 类的子类)被用来桥接数据源(即通过“R.array.zodiac”在代码中引用的字符串数组资源“zodiac”,图 94)和 View(即 Spinner)。ArrayAdapter 还负责为数据源中的每个项目创建一个 TextView。
-
在 AVD 上测试它,看看它是否如 图 99 所示工作。
图99:Spinner在工作! -
为了捕获从微调器中选择的项目以进行进一步处理,您必须为其附加一个“OnItemSelectedListener”。请按照以下步骤操作:
-
在 LinearLayout.java 类上实现“OnItemSelectedListener”接口。
// import android.widget.AdapterView; public class LinearLayout extends Activity implements AdapterView.OnItemSelectedListener { // ... other code ... }
-
实现“OnItemSelectedListener”接口的方法。
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { String selectedItem = parent.getItemAtPosition(position).toString(); Toast.makeText(parent.getContext(), selectedItem, Toast.LENGTH_LONG).show(); } public void onNothingSelected(AdapterView<?> parent) { }
-
在OnCreate方法中,将“setOnItemSelectedListener”附加到spinner对象。
Spinner spinner = (Spinner) findViewById(R.id.zodiac_spinner); // set a listener on spinner spinner.setOnItemSelectedListener(this);
-
在旋转器上捕获项目选中事件的完整代码如图 100 所示。
图100:在Spinner上设置OnItemSelectedListener
-
-
在AVD上运行它,从旋转器中选择一个项目(图101),它应该会回显所选生肖的名称(图102)。
图101:选择“狮子座”图102:回显“狮子座”
AutoCompleteTextView
当您在Google搜索框中输入时,您会得到一个下拉列表中出现的建议词列表。这就是自动完成。Android框架使用AutoCompleteTextView提供了类似的功能。AutoCompleteTextView是一个类似于EditText的View,它增加了在用户输入时自动显示来自某个数据源的建议词列表的功能。您将构建一个AutoCompleteTextView,它从我们在Spinner练习中使用的生肖名称列表中提取建议词。
-
在“设计”视图中打开“activity_linear_layout.xml”,拖动一个AutoCompleteTextView控件(位于“调色板”的Expert部分下方)并将其放置在Spinner下方(图103)。
图103:activity_linear_layout.xml -
在“LinearLayout.java”中,创建一个ArrayAdapter并将其附加到旋转器,如图104所示。
图104:将AutoCompleteTextView绑定到数据源 -
在 AVD 上启动它,输入一个字母,然后观察 AutoCompleteTextView 的实际效果(图 105)
图105:AutoCompleteTextView在工作!
Progress Bar
当用户从互联网上传或下载大量内容时,在屏幕上显示进度条是一种常见做法。在 Android 中,进度条通过 ProgressDialog 类实现,它本身就是一个 UI。您将在 "RelativeLayout" 页面上创建一个进度条,并使其在按钮点击时模拟一个正在进行中的任务。
-
在“文本”视图中打开“activity_relative_layout.xml”,更改android:text属性并向
节点添加一个android:onClick属性,如下所示: android:text="Show Progress..." android:onClick="showProgress"
-
在“RelativeLayout.java”中,添加showProgress方法,如图106所示。当“显示进度...”按钮被点击时,将调用此方法。代码将实例化一个ProgressDialog对象并设置其一些属性,如setMessage和setProgressStyle。此ProgressDialog对象将在单独的线程中运行,因此它不会阻塞主UI线程。
图106:showProgress方法 -
在AVD上启动它,导航到RelativeLayout页面,点击“显示进度...”按钮,然后观察进度条的运行情况,如图107所示。
图107:进度条在工作!
挑剔的二人组
是时候认识一下挑剔的二人组了——DatePicker 和 TimePicker。它们是许多网络应用程序中常见的面孔,用于询问日期和时间信息。只需选择(点击)日期或时间,无需输入,从而避免了在代码中处理格式问题的麻烦。您将创建一个新的Activity来探索它们。
-
创建一个名为“DateTimePickers”的新 Activity,保持默认的 RelativeLayout 不变,但删除默认的 TextView。从“调色板”中拖放一个 DatePicker 和一个 TimePicker 到屏幕上(图 108)。
图108:挑剔二人组 -
打开“activity_date_time_pickers.xml”,您会看到如图 109 所示的 XML 代码。请注意 DatePicker 和 TimePicker 的 android:onClick 属性。
图109:activity_date_time_pickers.xml -
打开托管“activity_date_time_pickers.xml”的“DateTimePickers.java”,插入高亮显示的代码,如图110所示。当用户点击相应的控件时,将调用getDate和getTime方法以回显屏幕上选定的日期或时间。
图110:处理点击事件的方法 -
再次强调,在您可以测试运行它之前,它必须从“MainActivity”页面导航。让我们为此目的设置“MainActivity”页面中的“Pickers”按钮。
-
在“文本”视图中打开“activity_main.xml”。
- 将此行添加到第四个 节点
android:onClick="getDateTimePickers"
-
将此方法添加到“MainActivity.java”
public void getDateTimePickers(View view) { Intent intent = new Intent(getApplicationContext(), DateTimePickers.class); startActivity(intent); }
大功告成!
-
-
运行它,选择一个日期或时间,然后点击其中一个。请参见图 111。
图111:拾取器在工作!
ListView
ListView 是一个 ViewGroup,它通过 Adapter 显示来自数据源的可滚动项目列表。Adapter 充当中介,从数组或数据库等数据源中提取数据行,并将每行数据转换为 View,然后将其插入到 ListView 中。每行中的 View 可以不同,并且可以根据您的需要变得非常复杂(图 112)。您将在您的应用中构建一个 ListView,以显示我们在 Spinner 练习中使用的生肖名称列表。
![]() |
图112:适配器解释(点击图片观看视频)
|
-
创建一个名为“ListViewActivity”的新Activity,删除屏幕上的任何默认布局或视图,从“调色板”中拖放一个ListView到屏幕上(图113)。
图113:activity_list_view.xml -
打开托管“activity_list_view.xml”的“ListViewActivity.java”,插入高亮显示的代码,如图114所示。
图114:将ListView绑定到数据源 -
在您可以测试运行它之前,它必须从“MainActivity”页面导航。让我们为此目的设置“MainActivity”页面中的“ListView”按钮。
-
在“文本”视图中打开“activity_main.xml”。
- 将此行添加到第四个 节点
android:onClick="getListViewPage"
-
将此方法添加到“MainActivity.java”
public void getListViewPage(View view) { Intent intent = new Intent(getApplicationContext(), ListViewActivity.class); startActivity(intent); }
大功告成!
-
-
运行它,您应该会看到这个(图115)
图115:ListView在工作!
GridView
GridView是一个ViewGroup,它以2D可滚动网格显示项目,网格项目通过ListAdapter(Adapter类的子类)从数据源获取。您将在您的应用中构建一个GridView来显示一个2D图像缩略图网格。每当选中一个项目时,它将回显图像的索引号。
-
您可以使用“sample_photos.zip”中的示例图像进行此练习。只需下载、解压缩,然后将照片移动到“res/drawable”文件夹中。
-
创建一个名为“GridViewActivity”的新Activity,删除屏幕上的任何默认布局或视图,从“调色板”中拖放一个GridView到屏幕上,并根据需要输入“activity_grid_view.xml”中的各种属性,如图116所示。
图116:activity_grid_view.xml -
打开托管“activity_grid_view.xml”的“GridViewActivity.java”,插入高亮显示的代码,如图117所示。GridView通过findViewById方法捕获。然后setAdapter方法将自定义ImageAdapter设置为此GridView中所有要显示项目的源。下一步将是创建这个ImageAdapter类。
图117:通过ImageAdapter将GridView绑定到图像源 -
按照图 118 中的步骤在当前项目中创建一个名为“ImageAdapter”的新 Java 类,然后将以下代码输入到该类中。ImageAdapter 类为图像数组“imageIds”中的每个图像创建一个 ImageView 对象,并定义其属性,例如 GridView.LayoutParams(180, 180) 设置 ImageView 的高度和宽度。
图118:创建新的Java类package com.example.peterleow.androiduis; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.GridView; import android.widget.ImageView; public class ImageAdapter extends BaseAdapter { private Context context; public ImageAdapter(Context c) { context = c; } public int getCount() { return imageIds.length; } public Object getItem(int position) { return null; } public long getItemId(int position) { return 0; } // create a new ImageView per image item public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView; if (convertView == null) { imageView = new ImageView(context); imageView.setLayoutParams(new GridView.LayoutParams(150, 150)); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setPadding(10, 10, 10, 10); } else { imageView = (ImageView) convertView; } imageView.setImageResource(imageIds[position]); return imageView; } private Integer[] imageIds = { R.drawable.photo_1, R.drawable.photo_2, R.drawable.photo_3, R.drawable.photo_4, R.drawable.photo_5, R.drawable.photo_6, R.drawable.photo_7, R.drawable.photo_8, R.drawable.photo_1, R.drawable.photo_2, R.drawable.photo_3, R.drawable.photo_4, R.drawable.photo_5, R.drawable.photo_6, R.drawable.photo_7, R.drawable.photo_8, R.drawable.photo_1, R.drawable.photo_2, R.drawable.photo_3, R.drawable.photo_4, R.drawable.photo_5, R.drawable.photo_6, R.drawable.photo_7, R.drawable.photo_8, R.drawable.photo_1, R.drawable.photo_2, R.drawable.photo_3, R.drawable.photo_4, R.drawable.photo_5, R.drawable.photo_6, R.drawable.photo_7 }; }
-
在您可以测试运行它之前,它必须从“MainActivity”页面导航。让我们为此目的设置“MainActivity”页面中的“GridView”按钮。
-
在“文本”视图中打开“activity_main.xml”。
- 将此行添加到第五个 节点
android:onClick="getGridViewPage"
-
将此方法添加到“MainActivity.java”
public void getGridViewPage(View view) { Intent intent = new Intent(getApplicationContext(), GridViewActivity.class); startActivity(intent); }
大功告成!
-
-
运行它,说声“茄子”!(图119)
图119:GridView在工作!
Reflection(反射)
我们快到休息站了。让我们暂停一下,反思一下。您是否注意到这组布局模型——LinearLayout、RelativeLayout和TableLayout,以及这组——ListView和GridView之间的区别。它们都组织UI上的元素。然而,相似之处仅限于此。
前一组主要处理按钮、微调器、文本字段等UI控件,这些控件通常在设计时以XML格式创建。
相反,后者的目的是以一维或二维网格形式列出数据,这些数据仅在运行时才可知。适配器充当中介,在将数据传递给 ListView 或 GridView 以供显示之前,先绘制和建模数据。
最佳实践
在整个旅程中,我引用了一些重要的学习要点、技巧和总结(适用之处)。特别是,我想强调以下三点作为最佳实践。
-
学习要点7 - 当您需要新的文本字符串时,不要硬编码。相反,您应该创建一个新的字符串资源,将该文本字符串作为值。然后,您可以在 XML 或代码中引用此字符串资源,只要您需要在任何 UI 上使用文本字符串。这是可重用性和可维护性的最佳实践。您应该始终参考图 37 至 41。
-
学习要点 11 - 将 Android Studio 默认提供的所有 android:id 值更改为更具描述性的名称。例如,不要使用“@+id/checkBox”或“@+id/checkBox2”,而是将“Jogging”复选框命名为“@+id/chkJogging”,将“Swimming”复选框命名为“@+id/chkSwimming”,以此类推。“chk”前缀是复选框的缩写。
- 您一直通过将 UI 布局声明为 XML 元素并将它们组织在 XML 文件中来构建 UI 布局。请保持这种方式!实际上,Android 框架允许您在运行时使用 Java 代码创建 UI 布局。但是,应尽可能避免这种方法,因为您会将应用程序的呈现方式与控制其行为的代码混杂在一起。这违反了“关注点分离”原则。
技巧
最后但同样重要的是,我想总结一些技巧,希望能让您的 Android 开发体验,尤其是使用 Android Studio 的体验,不再那么曲折。
-
始终尽早启动您的 AVD 并让它保持运行,当然,拥有更多的 RAM 和更快的处理器肯定有帮助,否则请使用真实设备
-
在两种方向上测试您的布局(如果允许),以确保您的 UI 按预期显示。
-
您的项目无法运行!?试试这些措施
-
红色代码通常表示缺少包。将光标放在上面并按 Alt + Enter 导入必要的包。
-
检查您的 XML 文件,确保所有节点结构良好,没有缺少节点。
-
在菜单栏上查找此菜单图标
,它显示“Sync Project with Gradle Files”以同步您的项目。
-
在菜单栏上,选择 Analyze > Inspect Code...,这将打开一个 Inspection 控制台,列出您的应用程序中所有潜在问题。如果您足够耐心和细致,您应该能够在此处找到错误(图 120)
图 120:GridView 运行中! -
最后的办法是什么?答案是“点击 File > Invalidate Caches / Restart... 然后祈祷!”
-
盘点
这段旅程似乎永无止境。我很高兴它结束了。您已经学习了 Android 中的许多 UI 布局和 UI 控件,并额外学习了一些处理简单交互的编码。您现在应该有足够的“能力”来使用 Java 代码组合 Android UI 并添加基本交互。我已将它们全部整理成一个快速链接列表,以便快速跳转到本文中的各种元素。
-
UI 布局
-
UI 控件
好好休息一下,我们还会再见面的。
P.S. 为了更专注地学习 Java,我鼓励您访问一些在线教程网站进行自学,例如,您可以尝试这个网站。最后一点,记得洗手。