Compose 中的焦点

当用户与您的应用互动时,他们通常会通过轻触屏幕上的元素来实现。不过,这并不是唯一的互动形式。其他形式的互动可能包括以下内容:

  • ChromeOS 用户可以使用实体键盘上的箭头键来导航屏幕。
  • 游戏玩家可以使用连接的游戏控制器来浏览游戏菜单。
  • 移动应用用户可以使用屏幕键盘循环切换元素。

在这些情况下,请务必跟踪在任何给定时间点处于活动状态的组件,我们称之为“焦点”。屏幕上的元素应按照逻辑顺序获得焦点。Jetpack Compose 具有默认的焦点处理方式,在大多数情况下,该方式都正确无误。但是,在某些情况下,您可能需要修改此默认行为。

以下页面介绍了如何在应用中使用焦点:

  • 更改焦点遍历顺序:介绍如何更改默认焦点顺序、添加焦点组和停用可组合项的焦点。
  • 更改焦点行为:说明如何请求、捕获和释放焦点,以及如何在进入屏幕时重定向焦点。
  • 对焦点做出反应:介绍如何对焦点变化做出反应、向元素添加视觉提示,以及了解元素的焦点状态。

默认焦点遍历顺序

在深入了解焦点搜索的默认行为之前,请务必了解层次结构中层级的概念:一般来说,我们可以说当两个 Composables 为同级时位于同一层级,这意味着它们具有相同的父级。例如,Column 中的元素处于同一级别。升级某个级别意味着从子级转到其 Composable 父级,或者按照相同的示例,从某个项返回到包含该层的 Column。相反,向下一级则相反,即从 Column 父级到所含项。此概念可应用于可包含其他 Composables 的每个 Composable

界面导航可以通过多种方式发生,其中大多数用户已经知道:

  • 标签页:一维导航(向前或向后)。Tab 导航可将焦点转到层次结构中的下一个或上一个元素。默认情况下,Compose 遵循 Composables 的声明。单向导航可通过键盘上的 tab 键或手表上的旋转边框实现,此类焦点搜索将访问屏幕上的每个元素。
  • 箭头键:二维导航,向左、向右、向上或向下箭头。 二维导航可通过电视上的方向键或键盘上的箭头键实现,其遍历顺序只会访问给定级别的元素。您可以使用方向键中间的方向键和返回按钮向下和返回到不同的级别。

以下面的屏幕截图为例,其中有四个按钮,一个接一个,并且您希望按显示顺序循环切换所有按钮。Jetpack Compose 提供了开箱即用的此行为:借助该工具包,您可以使用 tab 键从上到下按垂直顺序循环浏览每个可组合项,也可以通过按向上向下箭头移动焦点。

小屏幕设备上一个上下垂直排列的按钮列表的屏幕截图。
图 1. 小屏幕设备中显示的按钮列表

当您切换到其他类型的布局时,情况会略有变化。如果您的布局有多个列(例如下面的布局),Jetpack Compose 可让您在不添加任何代码的情况下在各列之间导航。如果您按 tab 键,Jetpack Compose 会自动按声明顺序(从第 1 个到第 4 个)突出显示这些项。使用键盘上的箭头键可选择在 2D 空间中按照所需的方向进行选择。

Column {
    Row {
        TextButton({ }) { Text("First field") }
        TextButton({ }) { Text("Second field") }
    }
    Row {
        TextButton({ }) { Text("Third field") }
        TextButton({ }) { Text("Fourth field") }
    }
}

Composables 在两个 Rows 中声明,并且焦点元素按从第一个到第四个的顺序声明。当您按 tab 键时,会生成以下焦点顺序:

屏幕截图:一个并排显示的按钮列表,位于较大的外形规格中,并排显示在两列中。
图 2. 更大外形规格中的按钮列表,并排显示在两列中

在下面的代码段中,您在 Columns 而不是 Rows 中声明了项目:

Row {
    Column {
        TextButton({ }) { Text("First field") }
        TextButton({ }) { Text("Second field") }
    }
    Column {
        TextButton({ }) { Text("Third field") }
        TextButton({ }) { Text("Fourth field") }
    }
}

此布局从屏幕的起始位置到结束位置,从上到下垂直遍历列表项:

屏幕截图:一个并排显示的按钮列表,位于较大的外形规格中,并排显示在两列中。
图 3. 更大外形规格中的按钮列表,并排显示在两列中

前面两个示例虽然单向导航不同,但在二维导航方面提供了相同的体验。这通常是因为在两个示例中,屏幕上的内容具有相同的地理位置。从第一个 Column 向右导航会将焦点移到第二个项目,从第一个 Row 向下导航会将焦点移到其下面的一个。