Kotlin Android 基础知识 10.3:面向所有人进行设计

此 Codelab 是“Android Kotlin 基础知识”课程的一部分。如果您按顺序学习这些 Codelab,您将会充分发掘此课程的价值。“Android Kotlin 基础知识”Codelab 着陆页列出了所有课程 Codelab。

简介

为了使大多数用户都能使用您的应用,无论您是出于娱乐目的还是出于商业目的进行开发,都是合理的。为此,您可以使用多个维度。

  • 支持 RTL 语言。欧洲及许多其他语言的从左到右书写,而源自这些语言区域的应用通常就是专为这些语言设计的。以其他语言从右到左读出的许多其他语言(例如阿拉伯语)提供其他语言。使用从右向左 (RTL) 书写的语言,吸引更多潜在用户。
  • 扫描无障碍功能。猜测他人可能会如何体验您的应用是一个潜在问题。Accessibility Scanner 应用消除了猜测的麻烦,并对其进行了分析,确定哪些方面可以改进其无障碍功能。
  • 设计 TalkBack 时需提供内容说明。视障比人们想象的更常见,许多用户(而不仅仅是盲人)使用屏幕阅读器。内容说明是屏幕阅读器在用户与屏幕元素互动时所说的短语。
  • 支持夜间模式。对于许多视力受损的用户来说,更改屏幕颜色可提高对比度,并帮助用户直观地使用您的应用。Android 可让您轻松支持夜间模式,并且您应始终支持夜间模式,为用户提供一种替代默认屏幕颜色的简单选择。

在此 Codelab 中,您将了解这些选项,并为 GDG Finder 应用添加相应支持。

您还将学习如何在 Android 应用中使用条状标签。您可以使用条状标签使应用更加有趣,同时使其保持可用。

您应当已掌握的内容

您应熟悉以下内容/操作:

  • 如何创建包含 activity 和 fragment 的应用,以及如何在传递数据的 fragment 之间导航。
  • 使用视图和视图组来布置界面,特别是 RecyclerView。
  • 如何将架构组件(包括 ViewModel)与推荐的架构结合使用,以构建结构清晰且高效的应用。
  • 数据绑定、协程以及如何处理鼠标点击。
  • 如何使用 Room 数据库连接到互联网并在本地缓存数据。
  • 如何设置视图属性,以及如何将资源提取到 XML 资源文件中并使用这些资源。
  • 如何使用样式和主题自定义应用的外观。
  • 如何使用 Material 组件、尺寸资源和自定义着色。

学习内容

  • 如何使您的应用可供尽可能多的用户使用。
  • 如何让应用使用从右到左 (RTL) 的语言。
  • 如何评估应用的无障碍功能。
  • 如何利用内容说明让您的应用更适合屏幕阅读器。
  • 如何使用条状标签。
  • 如何让应用以深色模式运行。

您将执行的操作

  • 评估并扩展给定应用,使其适用于 RTL 语言,从而改进无障碍功能。
  • 扫描您的应用,确定无障碍功能在哪些方面有待改进。
  • 使用图片内容描述。
  • 了解如何使用可绘制对象。
  • 为您的应用添加使用夜间模式的功能。

GDG Finder 入门版应用基于您在本课程中学到的所有内容。

该应用使用 ConstraintLayout 布局三个屏幕。其中两个屏幕只是布局文件,可供您用于在 Android 上探索颜色和文本。

第三个屏幕是 GDG 查找工具。GDG(简称“Google 开发者社区”)是专注于 Google 技术(包括 Android)的开发者社区。世界各地的 GDG 都会举办聚会、会议、研究 Jam 和其他活动。

开发此应用时,您需要处理真实的 GDG 列表。查找器屏幕会使用设备的位置信息按距离对 GDG 进行排序。

如果您手气不错,而且您所在的地区有一家 GDG,请查看该网站并报名参加他们的活动!GDG 活动是结识其他 Android 开发者以及了解本课程不适合的行业最佳做法的绝佳方式。

下面的屏幕截图显示了此 Codelab 从开始到结尾对您的应用有何影响。

从左到右 (LTR) 和从右到左 (RTL) 书写的语言的主要区别在于所显示内容的方向。当界面方向从 LTR 更改为 RTL(或相反)时,它通常称为镜像。镜像会影响大多数屏幕内容,包括文本、文本字段图标、布局以及带有方向的图标(例如箭头)。其他内容不会进行镜像处理,例如数字(时钟、电话号码)、没有方向的图标(飞行模式、Wi-Fi)、播放控件以及大多数图表和图形。

使用 RTL 文本方向的语言可供全球超过 10 亿人使用。Android 开发者遍布世界各地,因此 GDG Finder 应用必须支持 RTL 语言。

第 1 步:添加 RTL 支持

在此步骤中,您将让 GDG Finder 应用支持 RTL 语言。

  1. 下载并运行 GDGFinderMaterial 应用(本 Codelab 的起始应用),或者继续学习上一个 Codelab 中的最终代码。
  2. 打开 Android 清单。
  3. <application> 部分中,添加以下代码以指定应用支持 RTL。
<application
        ...
        android:supportsRtl="true">
  1. Design 标签页中,打开 activity_main.xml
  2. 用于预览的语言区域下拉菜单中,选择从右向左预览。(如果您找不到此菜单,请拓宽窗格或关闭属性窗格以发现该菜单。)

  1. 预览中,请注意标题“GDG 访达”已移到右侧,屏幕的其余部分基本保持不变。总体而言,此屏幕可通过。但是,文本视图中的对齐方式现在是错误的,因为它与左侧(而不是右侧)对齐。

  1. 如需在设备上执行此操作,请在设备或模拟器的设置开发者选项中选择强制使用从右到左的布局。(如果您需要开启开发者选项,请找到版本号,然后点击该数字,直到您看到一条内容为表示开发者的消息框。(因设备和 Android 系统版本而异)。

  1. 运行应用,并在设备上验证主屏幕与预览中显示的屏幕是否相同。请注意,FAB 现在切换到了左侧,而 Hamburger 菜单在右侧!
  2. 在该应用中,打开抽屉式导航栏并转到搜索屏幕。如下所示,这些图标仍在左侧,不会显示任何文字。结果是,文本位于屏幕之外,位于图标的左侧。这是因为代码在视图属性和布局约束中使用左/右屏幕引用。

第 2 步:使用开始和结束值,而非左右两侧

屏幕上的“左”和“右”与屏幕方向一致,即使文本方向发生变化,也不会改变。例如,layout_constraintLeft_toLeftOf 始终会将元素的左侧约束为屏幕的左侧。在您的应用示例中,文本以 RTL 语言离开屏幕,如上方屏幕截图所示。

为解决此问题,请使用“Start”和“End”这两个术语,而不要使用“左”和“右”。该术语根据当前语言的文本设置适当的文本开头和结尾,以使外边距和布局位于屏幕的正确区域。

  1. Open list_item.xml
  2. 将对 LeftRight 的所有引用替换为对 StartEnd 的引用。
app:layout_constraintStart_toStartOf="parent"

app:layout_constraintStart_toEndOf="@+id/gdg_image"
app:layout_constraintEnd_toEndOf="parent"
  1. ImageViewlayout_marginLeft 替换为 layout_marginStart。这会将外边距移到正确的位置,使图标脱离屏幕边缘。
<ImageView
android:layout_marginStart="
?
  1. 打开 fragment_gdg_list.xml。在预览窗格中查看 GDG 列表。请注意,此图标仍在朝向错误的方向,因为它已被镜像。(如果该图标未被镜像,请确保您仍在查看从右到左的预览。)根据 Material Design 指南,不应对图标进行镜像。
  2. 打开 res/drawable/ic_gdg.xml
  3. 在 XML 代码的第一行中,找到并删除 android:autoMirrored="true" 以停用镜像。
  4. 查看预览或再次运行应用,然后打开“搜索 GDG”屏幕。布局现在应该已得到修复!

第 3 步:让 Android Studio 为您完成工作

在之前的练习中,您已迈出支持 RTL 语言的第一步。幸运的是,Android Studio 可以扫描您的应用并为您设置大量基础知识。

  1. list_item.xmlTextView 中,将 layout_marginStart 更改回 layout_marginLeft,以便扫描器能够找到某些内容。
<TextView
android:layout_marginLeft="@dimen/spacing_normal"
  1. 在 Android Studio 中,选择 Refactor > Add RTL support where necessary,并选中用于更新清单的复选框以及用于使用开始和结束属性的布局文件。

  1. Refactoring Preview 窗格中,找到 app 文件夹,然后展开,直到打开所有详细信息。
  2. 请注意,在应用文件夹下,您刚刚更改的 layout_marginLeft 被列为要重构的代码。

  1. 请注意,预览还会列出系统和库文件。右键点击布局loutout-watch-v20 以及不属于 app 的其他任何文件夹,然后从上下文菜单中选择排除

  1. 现在,请执行重构。(如果您看到有关系统文件的弹出式窗口,请确保您已排除不属于应用代码的所有文件夹。)
  1. 请注意,layout_marginLeft 已更改回 layout_marginStart

第 3 步:浏览语言区域文件夹

到目前为止,您刚刚更改了应用的默认语言方向。对于正式版应用,您需要将 strings.xml 文件发送给翻译人员,使其翻译成新的语言。在此 Codelab 中,该应用提供了一个西班牙语的 strings.xml 文件(我们使用 Google 翻译来生成译文,因此这些译文并不完美)。

  1. 在 Android Studio 中,将项目视图切换为 Project Files
  2. 展开 res 文件夹,并注意 res/valuesres/values-es 的文件夹。文件夹名称中的“queses”是西班牙语的语言代码values-"language code" 文件夹中包含每种受支持的语言的值。不带扩展名的 values 文件夹包含以其他方式应用的默认资源。

  1. values-es 中,打开 strings.xml 并注意所有字符串均为西班牙语。
  2. 在 Android Studio 中,打开 Design 标签页中的 activity_main.xml
  3. 语言区域预览下拉列表中,选择西班牙语。您的文字现在应该为西班牙语。

  1. [可选]如果您精通 RTL 语言,请创建一个采用该语言的 values 文件夹和 strings.xml,并测试其在设备上的显示效果。
  2. [可选] 更改设备上的语言设置并运行应用。 请勿将设备的语言更改为自己不懂的语言,因为撤消之后会有些困难!

在上一个任务中,您手动更改了应用,然后使用 Android Studio 检查是否还需进行其他 RTL 改进。

要改进您的应用的无障碍功能,无障碍功能扫描仪应用是您的最佳助手。它会扫描目标设备上的应用,并提出改进建议,例如增大触摸目标、提高对比度以及提供图片说明,使您的应用使用起来更没有障碍。无障碍功能扫描仪由 Google 打造,您可以从 Play 商店安装。

第 1 步:安装并运行无障碍功能扫描仪

  1. 打开 Play 商店并在必要时登录。您可以在实体设备或模拟器上执行此操作。此 Codelab 使用模拟器。
  1. 在 Play 商店中搜索 Accessibility Scanner by Google LLC。请务必获取 Google 签发的正确应用,因为任何扫描都需要获得大量权限!

  1. 在模拟器上安装扫描仪。
  2. 安装完毕后,点击打开
  3. 点击开始使用
  4. 点击确定,在“设置”中开始设置无障碍功能扫描仪。

  1. 点击无障碍功能扫描仪以转到设备的无障碍设置。

  1. 点击使用服务启用该服务。

  1. 按照屏幕上的说明操作并授予所有权限。
  2. 然后点击知道了,返回主屏幕。您可能会在屏幕上的某个位置看到一个带对勾标记的蓝色按钮。点击此按钮即可在前台触发应用的测试。您可以通过拖动按钮来调整其位置。此按钮会始终显示在任何应用上,因此您可以随时触发测试。

  1. 打开或运行您的应用。
  2. 点击蓝色按钮并接受其他安全警告和权限。

当您首次点击无障碍功能扫描仪图标时,该应用会请求您授予相关权限,以获取屏幕上显示的所有内容。这似乎是非常可怕的权限。

您基本上不应该授予这样的权限,因为该权限可以让应用读取您的电子邮件,甚至抓取您的银行账户信息!不过,为了让无障碍功能扫描仪能够正常工作,它需要像用户那样检查您的应用 - 这就是它需要此权限的原因。

  1. 点击蓝色按钮并等待分析完成。您将看到与以下屏幕截图类似的内容,其标题和 FAB 方框显示为红色。这表示在此屏幕上针对无障碍功能改进给出了两条建议。

  1. 点击 GDG Finder 周围的方框。系统会打开一个窗格,其中包含更多信息(表示图片对比度存在问题),如下所示。
  2. 您只需展开图片对比度信息,该工具便会提供建议的补救措施。
  3. 点击右侧的箭头可获取下一项内容的信息。

  1. 在您的应用中,导航到 Apply for GDG 屏幕,然后使用无障碍功能扫描仪应用进行扫描。此选项提供了很多建议,如下所示。12 确切地说,为了公平公正,其中有些商品与类似商品重复。
  2. 点击底部工具栏中的“堆栈” 图标,以获取所有建议的列表,如右侧屏幕截图中所示。在本 Codelab 中,您将解决所有这些问题。

Android 无障碍套件是 Google 推出的一系列应用套件,其中包含各种工具,可帮助提升应用的无障碍水平。其中包括 TalkBack 等工具。TalkBack 是一款屏幕阅读器,可提供听觉、触感和语音反馈,让用户能够在自己的屏幕上导航和使用内容。

事实证明,TalkBack 不仅适用于盲人,而且也适用于许多患有某种视力障碍的许多人。甚至只是想好好休息一下!

无障碍功能是面向所有用户的!在此任务中,您将试用 TalkBack 并更新应用,使其能正常运行。

第 1 步:安装并运行无障碍套件

TalkBack 已预安装在许多实体设备上,但在模拟器上,您需要安装 TalkBack。

  1. 打开 Play 商店。
  2. 找到无障碍套件。请确保这是 Google 提供的正确应用。
  3. 如果未安装,请安装无障碍套件。
  4. 如需在设备上启用 TalkBack,请依次转到设置 &无障碍,然后选择使用服务,即可开启 TalkBack。与无障碍功能扫描仪一样,TalkBack 需要获取相关权限才能读取屏幕上的内容。在您接受权限请求后,TalkBack 会向您提供一系列教程,帮助您了解如何有效地使用 TalkBack。
  5. 暂停后,请学习教程,如果除此之外没有其他方法,则可以了解如何在完成时关闭 TalkBack。
  6. 如需退出教程,请点击返回按钮将其选中,然后在屏幕上的任意位置点按两次。
  1. 探索如何使用具有 TalkBack 功能的 GDG Finder 应用。请注意,TalkBack 没有提供关于屏幕或控件的有用信息。您将在下一个练习中解决此问题。

第 2 步:添加内容说明

内容描述符是用于说明视图含义的描述性标签。您的大部分观看次数都应该包含内容说明。

  1. 在运行 GDG Finder 应用并启用 Talback 后,转到申请运行 GDG 屏幕。
  2. 点按主图片,什么都不会发生。
  3. 打开 add_gdg_fragment.xml
  4. ImageView 中,添加内容描述符属性,如下所示。strings.xml 中为您提供了 stage_image_description 字符串。
android:contentDescription="@string/stage_image_description"
  1. 运行应用。
  2. 转到申请运行 GDG,然后点击该图片。现在,您应该会听到图片的简短说明。
  3. [可选] 为此应用中的其他图片添加内容说明。在正式版应用中,所有图片都需要有内容说明。

第 3 步:向可修改的文本字段添加提示

对于可修改的元素(例如 EditText),您可以在 XML 中使用 android:hint 来帮助用户确定要输入的内容。提示始终会在界面中显示,因为它是输入字段中的默认文本。

  1. 仍在 add_gdg_fragment.xml 中。
  2. 添加内容说明和提示,使用以下代码作为指导。

添加到 textViewIntro

android:contentDescription="@string/add_gdg"

分别向编辑文本添加:

android:hint="@string/your_name_label"

android:hint="@string/email_label"

android:hint="@string/city_label"

android:hint="@string/country_label"

android:hint="@string/region_label"
  1. labelTextWhy 添加内容说明。
android:contentDescription="@string/motivation" 
  1. EditTextWhy 添加提示。为编辑框添加标签后,向相应标签添加内容说明和提示。
android:hint="@string/enter_motivation"
  1. 为提交按钮添加内容说明。所有按钮都需要说明按下时会出现什么情况。
android:contentDescription="@string/submit_button_description"
  1. 在启用 Talback 的情况下运行您的应用,然后填写申请表单以运行 GDG。

第 4 步:创建内容组

对于 TalkBack 视为群组的界面控件,您可以使用内容分组。相关内容会一起公布。这样一来,辅助技术的用户无需滑动、扫描或等待,即可在屏幕上找到所有信息。这不会影响控件在屏幕上的显示方式。

如需对界面组件进行分组,请将其封装到 ViewGroup 中,例如 LinearLayout。在 GDG 访达应用中,labelTextWhyeditTextWhy 元素非常适合通过分组方式分组,因为它们在语义上是一致的。

  1. 打开 add_gdg_fragment.xml
  2. LinearLayout 封装在 LabelTextWhyEditTextWhy 周围,以创建内容组。复制并粘贴以下代码。此 LinearLayout 已包含您需要的部分样式。(请确保 button 超出 LinearLayout。)
<LinearLayout android:id="@+id/contentGroup" android:layout_width="match_parent"
            android:layout_height="wrap_content" android:focusable="true"
            app:layout_constraintTop_toBottomOf="@id/EditTextRegion"
            android:orientation="vertical" app:layout_constraintStart_toStartOf="@+id/EditTextRegion"
            app:layout_constraintEnd_toEndOf="@+id/EditTextRegion"
            android:layout_marginTop="16dp" app:layout_constraintBottom_toTopOf="@+id/button"
            android:layout_marginBottom="8dp">

     <!-- label and edit text here –>

<LinearLayout/>
  1. 选择代码 > 重新格式化代码,正确缩进所有代码。
  2. 移除 labelTextWhyeditTextWhy 中的所有布局外边距。
  3. labelTextWhy 中,将 layout_constraintTop_toTopOf 约束条件更改为 contentGroup
app:layout_constraintTop_toTopOf="@+id/contentGroup" />
  1. editTextWhy 中,将 layout_constraintBottom_toBottomOf 约束条件更改为 contentGroup
app:layout_constraintBottom_toBottomOf="@+id/contentGroup"
  1. EditTextRegionButton 约束到 contentGroup 以消除错误。
app:layout_constraintBottom_toTopOf="@+id/contentGroup"
  1. LinearLayout 添加外边距。(可选)将此外边距作为维度提取。
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"

如果需要帮助,请对照解决方案代码中的 add_gdg_fragment.xml 检查您的代码。

  1. 运行您的应用,并借助 TalkBack 探索申请运行 GDG 屏幕。

第 5 步:添加动态区域

目前,提交按钮上的标签为正常。如果按钮在表单提交之前只有一个标签和说明,并且在用户点击并提交表单后动态更改为其他标签和内容说明,效果会更好。您可以使用动态区域执行此操作。

实时区域会向无障碍服务指明是否应在视图发生更改时通知用户。例如,通知用户密码不正确或网络连接错误是提高应用易用性的好方法。为简单起见,在此示例中,您需要在提交按钮更改状态时通知用户。

  1. 打开 add_gdg_fragment.xml
  2. 使用提供的 submit 字符串资源,将按钮的文本赋值更改为 Submit
android:text="@string/submit"
  1. 通过设置 android:accessibilityLiveRegion 属性向该按钮添加动态区域。输入时,您有多个值选项。根据更改的重要性,您可以选择是否打断用户。使用值“assertive”时,无障碍服务会中断正在进行的语音操作,立即宣布对此视图的更改。如果您将值设置为“none”,系统不会播报任何更改。如果设为“礼让”,无障碍服务会读出更改,但请稍候。将值设为“礼让”。

android:accessibilityLiveRegion="polite"
  1. add 软件包中,打开 AddGdgFragment.kt
  2. showSnackBarEvent Observer 内,显示 SnackBar 之后,为按钮设置新的内容说明和文本。
binding.button.contentDescription=getString(R.string.submitted)
binding.button.text=getString(R.string.done)
  1. 运行您的应用,然后点击该按钮。很遗憾,按钮和字体太小!

第 6 步:修正按钮样式

  1. add_gdg_fragment.xml 中,将按钮的 widthheight 更改为 wrap_content,以便显示完整标签并调整按钮的尺寸。
android:layout_width="wrap_content"
android:layout_height="wrap_content"
  1. 从按钮中删除 backgroundTinttextColortextSize 属性,以便应用使用更好的主题样式。
  2. textViewIntro 中删除 textColor 属性。主题颜色应具有良好的对比度。
  3. 运行应用。请注意 Submit 按钮的易用性大大提高。点击 Submit(提交)并注意该值会如何变为 Done(完成)。

信息块是表示属性、文本、实体或操作的紧凑元素。用户可输入信息、选择相应选项、过滤内容或触发操作。

Chip 微件是 ChipDrawable 的瘦视图封装容器,其中包含所有布局和绘制逻辑。此额外的逻辑支持触摸、鼠标、键盘和无障碍功能导航。主贴块和关闭图标被视为独立的逻辑子视图,并且包含它们自己的导航行为和状态。

贴块使用可绘制对象。Android 可绘制对象可让您在屏幕上绘制图像、形状和动画,它们的大小可以固定,也可以动态大小。您可以将图片用作可绘制对象,例如 GDG 应用中的图片。您还可以使用矢量绘图绘制任何您能想到的内容。此 Codelab 并未涵盖可调整大小的可绘制对象,称为 9-patch 可绘制对象drawable/ic_gdg.xml 中的 GDG 徽标是另一种可绘制对象。

可绘制对象不是视图,因此您不能直接将可绘制对象放在 ConstraintLayout 中,而需要将其放在 ImageView 中。您还可以使用可绘制对象为文本视图或按钮提供背景,这些背景会在文本后方绘制。

第 1 步:在 GDG 列表中添加贴块

下面选中的条状标签使用了三个可绘制对象。背景和对勾标记都是可绘制对象。触摸条状标签会产生涟漪效果,这是使用特殊 RippleDrawable 完成的,可显示涟漪效果来响应状态变化。

在此任务中,您将向 GDG 列表添加条状标签,并让这些部分在选中后更改状态。在本练习中,您将在搜索屏幕顶部添加一个名为“条状标签”的按钮。每个按钮都会过滤 GDG 列表,让用户只能看到来自所选区域的结果。选择某个按钮后,该按钮的背景会发生变化,并会显示对勾标记。

  1. 打开 fragment_gdg_list.xml
  2. HorizontalScrollView. 内创建一个 com.google.android.material.chip.ChipGroup,将其 singleLine 属性设置为 true,这样,所有条状标签排列在一条水平可滚动线上。将 singleSelection 属性设置为 true,以便一次仅选择组中的一个条状标签。代码如下。
<com.google.android.material.chip.ChipGroup
    android:id="@+id/region_list"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:singleSelection="true"
    android:padding="@dimen/spacing_normal"/>
  1. layout 文件夹中,创建一个名为 region.xml 的新布局资源文件,用于定义一个 Chip 的布局。
  2. 在 region.xml 中,将所有代码替换为一个 Chip 的布局,如下所示。请注意,此 Chip 是一个 Material 组件。另请注意,您可以通过设置属性 app:checkedIconVisible 来获取对勾标记。您会收到缺少 selected_highlight 颜色的错误。
<?xml version="1.0" encoding="utf-8"?>

<com.google.android.material.chip.Chip
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@style/Widget.MaterialComponents.Chip.Choice"
        app:chipBackgroundColor="@color/selected_highlight"
        app:checkedIconVisible="true"
        tools:checked="true"/>
  1. 如需创建缺少的 selected_highlight 颜色,请将光标放在 selected_highlight 上,调出 intent 菜单,然后为所选突出显示的内容创建颜色资源。默认选项没有问题,因此只需点击确定即可。该文件在 res/color 文件夹中创建。
  2. 打开 res/color/selected_highlight.xml。在此颜色状态列表中,编码为 <selector>,您可以为不同状态提供不同的颜色。每种状态及相关颜色都编码为 <item>。如需详细了解这些颜色,请参阅颜色主题
  1. <selector> 中,将采用默认颜色 colorOnSurface 的项添加到状态列表中。在状态列表中,请务必始终涵盖所有状态。其中一种方法是使用默认颜色。
<item android:alpha="0.18" android:color="?attr/colorOnSurface"/>
  1. 在默认颜色上方,添加颜色为 colorPrimaryVariantitem,并将其状态限制为所选状态为 true 时的状态。状态列表从上到下依次显示,就像案例语句一样。如果没有任何状态匹配,则应用默认状态。
<item android:color="?attr/colorPrimaryVariant"
         android:state_selected="true" />

第 2 步:显示条状标签行

GDG 应用会创建一个条状标签,列出拥有 GDG 的区域。选择条状标签后,应用会过滤结果,仅显示相应区域的 GDG 结果。

  1. search 软件包中,打开 GdgListFragment.kt
  2. onCreateView() 中的 return 语句正上方,在 viewModel.regionList 上添加观察器并替换 onChanged()。当视图模型提供的区域列表发生变化时,需要重新创建芯片。添加一个在提供的 datanull 时立即返回的语句。
viewModel.regionList.observe(viewLifecycleOwner, object: Observer<List<String>> {
        override fun onChanged(data: List<String>?) {
             data ?: return
        }
})
  1. onChanged() 内的 null 测试下方,将 binding.regionList 赋值给名为 chipGroup 的新变量,以缓存 regionList
val chipGroup = binding.regionList
  1. 在下方,创建一个新的 layoutInflator,用于膨胀来自 chipGroup.context 的条状标签。
val inflator = LayoutInflater.from(chipGroup.context)
  1. 清理并重建项目以消除数据绑定错误。

在 inflator 下方,您现在可以创建实际的条状标签,每个标签对应 regionList 中的一个区域。

  1. 创建一个用于保存所有贴块的变量 children。为它传递的 data 赋值一个映射函数,可以创建并返回每个条状标签。
val children = data.map {} 
  1. 在地图 lambda 内,为每个 regionName 创建并扩充条状标签。完成后的代码如下所示。
val children = data.map {
   val children = data.map { regionName ->
       val chip = inflator.inflate(R.layout.region, chipGroup, false) as Chip
       chip.text = regionName
       chip.tag = regionName
       // TODO: Click listener goes here.
       chip
   }
}
  1. 在 lambda 内,在返回 chip 之前,添加一个点击监听器。点击 chip 时,请将其状态设为 checked。在 viewModel 中调用 onFilterChanged(),这会触发一系列事件来获取此过滤器的结果。
chip.setOnCheckedChangeListener { button, isChecked ->
   viewModel.onFilterChanged(button.tag as String, isChecked)
}
  1. 在 lamba 结束时,从 chipGroup 中移除当前的所有视图,然后将 children 中的所有条状标签添加到 chipGroup。(您无法更新条状标签,因此必须移除并重新创建 chipGroup 的内容。)
chipGroup.removeAllViews()

for (chip in children) {
   chipGroup.addView(chip)
}

完成后的观察器应如下所示:

   override fun onChanged(data: List<String>?) {
       data ?: return

       val chipGroup = binding.regionList
       val inflator = LayoutInflater.from(chipGroup.context)

       val children = data.map { regionName ->
           val chip = inflator.inflate(R.layout.region, chipGroup, false) as Chip
           chip.text = regionName
           chip.tag = regionName
           chip.setOnCheckedChangeListener { button, isChecked ->
               viewModel.onFilterChanged(button.tag as String, isChecked)
           }
           chip
       }
       chipGroup.removeAllViews()

       for (chip in children) {
           chipGroup.addView(chip)
       }
   }
})
  1. 运行您的应用,然后搜索 GDGS 以打开搜索屏幕,以使用您的新条状标签。点击各个条状标签后,该应用下方会显示过滤条件组。

夜间模式可让您的应用将其颜色更改为深色主题,例如当设备设置设为启用夜间模式时。在夜间模式下,应用会将默认的浅色背景更改为深色,并相应地更改所有其他屏幕元素。

第 1 步:启用夜间模式

如需为应用提供深色主题,您可以将其主题从 Light 主题更改为名为 DayNight 的主题。DayNight 主题会显示为浅色或深色,具体取决于模式。

  1. styles.xml, 中,将 AppTheme 父主题从 Light 更改为 DayNight
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
  1. MainActivityonCreate() 方法中,调用 AppCompatDelegate.setDefaultNightMode() 以编程方式开启深色主题。
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
  1. 运行应用,验证其是否已切换为深色主题。

第 2 步:生成您自己的深色主题调色板

如需自定义深色主题,请创建带有 -night 限定符的文件夹以使用深色主题。例如,您可以创建名为 values-night 的文件夹,从而在夜间模式下设置特定的颜色。

  1. 访问 material.io 颜色选择器工具并创建夜间主题调色板。例如,您可以将其设置为深蓝色。
  2. 生成并下载 colors.xml 文件。
  3. 切换到 Project Files 视图,列出项目中的所有文件夹。
  4. 找到 res 文件夹并将其展开。
  5. 创建一个 res/values-night 资源文件夹。
  6. 将新的 colors.xml 文件添加到 res/values-night 资源文件夹中。
  7. 在启用夜间模式的情况下运行应用,应用应使用您为 res/values-night 定义的新颜色。请注意,这些贴块使用新的次要颜色。

Android Studio 项目:GDGFinderFinal

支持 RTL 语言

  • 在 Android 清单中,设置 android:supportsRtl="true"
  • 您可以在模拟器中预览 RTL,并且可以使用自己的语言检查屏幕布局。在设备或模拟器上,打开设置,然后在开发者选项中选择强制使用从右到左的布局
  • 将对 LeftRight 的引用替换为对 StartEnd 的引用。
  • 通过删除 android:autoMirrored="true" 来停用可绘制对象的镜像。
  • 选择 Refactor > Add RTL support where necessary,Android Studio 将为您代劳。
  • 使用 values-"language code" 文件夹来存储特定于语言的资源。

扫描无障碍功能

TalkBack 与内容说明的设计

  • 安装 Google 提供的 Android 无障碍套件,其中包括 TalkBack。
  • 为所有界面元素添加内容说明。例如:
    android:contentDescription="@string/stage_image_description"
  • 对于 EditText 等可修改元素,请在 XML 中使用 android:hint 属性,为用户提供关于输入内容的提示。
  • 通过将相关元素封装到视图组中,来创建内容组。
  • 通过 android:accessibilityLiveRegion 创建动态区域,为用户提供其他反馈。

使用贴块实现过滤器

  • 信息块是表示属性、文本、实体或操作的紧凑元素。
  • 如需创建芯片组,请使用 com.google.android.material.chip.ChipGroup
  • 定义一个 com.google.android.material.chip.Chip 的布局。
  • 如果您想让条状标签更改颜色,请以包含有状态颜色的 <selector> 的形式提供颜色状态列表:
    <item android:color="?attr/colorPrimaryVariant"
    android:state_selected="true" />
  • 通过向视图模型中的数据添加观察者,将贴块绑定到实时数据。
  • 如需显示条状标签,请为条状标签组创建膨胀器:
    LayoutInflater.from(chipGroup.context)
  • 创建条状标签,添加用于触发所需操作的点击监听器,然后将条状标签添加到芯片组。

支持深色模式

  • 使用 DayNight AppTheme 支持深色模式。
  • 您可以通过编程方式设置深色模式:
    AppCompatDelegate.setDefaultNightMode()
  • 创建一个 res/values-night 资源文件夹,为深色模式提供自定义颜色和值。

Android 开发者文档:

其他资源:

此部分列出了在由讲师主导的课程中,学生学习此 Codelab 后可能需要完成的家庭作业。讲师自行决定是否执行以下操作:

  • 根据需要布置作业。
  • 告知学生如何提交家庭作业。
  • 给家庭作业评分。

讲师可以酌情采纳这些建议,并且可以自由布置自己认为合适的任何其他家庭作业。

如果您是在自学此 Codelab,可随时通过这些家庭作业来检测您的知识掌握情况。

问题 1

要支持 RTL 语言,以下执行以下哪项操作?

▢ 将属性中的 LeftRight 替换为 StartEnd

▢ 改用 RTL 语言

▢ 确保所有图标都使用 android:autoMirrored="true"

▢ 提供内容说明

问题 2

大多数 Android 设备都内置了以下哪些无障碍工具?

▢ TalkBack

▢ 无障碍功能扫描仪

▢ 在 Android Studio 中,重构 > 尽可能添加 RTL 支持

问题 3

以下关于薯条的说法中,哪一项是错误的?

▢ 您以 ChipGroup 的一部分显示贴块。

▢ 您可以为 ChipGroup 提供颜色状态列表。

▢ 组件是表示输入、属性或操作的紧凑元素。

如果您的应用使用芯片,则必须始终启用 DarkTheme

问题 4

为深色主题和浅色模式设置哪个主题背景?

DayNight

DarkTheme

DarkAndLightTheme

Light

问题 5

什么是动态区域?

▢ 包含对用户很重要的节点

▢ 根据 Material 准则改变形状的屏幕区域

▢ 可在线播放视频的视图

▢ 动画可绘制对象