[20250908]Android Talkback 自定义合并
Android Talkback 自定义合并
TalkBack 等无障碍服务按元素在屏幕中导航。默认情况下,Jetpack Compose 中至少设置了一个语义属性的每个低级可组合项会获得焦点。例如,Text 可组合项设置了 text 语义属性,因此会获得焦点。
不过,如果屏幕上有太多可聚焦的元素,当用户逐个浏览这些元素时,会导致混乱。我们可以使用 semantics 修饰符及其 mergeDescendants 属性将可组合项合并在一起。
让我们看一下文章屏幕。大多数元素都获得了正确级别的焦点。但是,文章的元数据目前是作为几个单独的项目朗读的。可以通过将其合并为一个可聚焦实体来加以改进:
之前
@Composable
private fun PostMetadata(metadata: Metadata) {// ...Row {Image(// ...)Spacer(Modifier.width(8.dp))Column {Text(// ...)CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant) {Text(// ..)}}}
}
之后
@Composable
private fun PostMetadata(metadata: Metadata) {// ...Row(Modifier.semantics(mergeDescendants = true) {}) {Image(// ...)Spacer(Modifier.width(8.dp))Column {Text(// ...)CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant) {Text(// ..)}}}
}
来源
当 TalkBack 选定 Switch 和 Checkbox 等可切换元素时,会大声读出其选中状态。不过,如果没有上下文,就很难理解这些可切换元素指的是什么。我们可以通过提升可切换状态来包含可切换元素的上下文,这样用户就可以通过按可组合项本身或描述它的标签来切换 Switch 或 Checkbox。
我们可以在“Interests”屏幕中看到一个这样的例子。您可以从主屏幕中打开抽屉式导航栏来导航到该屏幕。在“Interests”屏幕上,有用户可以订阅的主题列表。默认情况下,此屏幕上的复选框与其标签是分开聚焦的,这使得很难理解其上下文。我们希望整个 Row 可切换:
使用复选框。之前(左侧)与之后(右侧)的比较。
之前
@Composable
private fun TopicItem(itemTitle: String, selected: Boolean, onToggle: () -> Unit) {// ...Row(modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)) {// ...Checkbox(checked = selected,onCheckedChange = { onToggle() },modifier = Modifier.align(Alignment.CenterVertically))}
}
@Composable
private fun TopicItem(itemTitle: String, selected: Boolean, onToggle: () -> Unit) {// ...val stateNotSubscribed = stringResource(R.string.state_not_subscribed)val stateSubscribed = stringResource(R.string.state_subscribed)Row(modifier = Modifier.semantics {stateDescription = if (selected) {stateSubscribed} else {stateNotSubscribed}}.toggleable(value = selected,onValueChange = { _ -> onToggle() },role = Role.Checkbox).padding(horizontal = 16.dp, vertical = 8.dp)) {// ...Checkbox(checked = selected,onCheckedChange = null,modifier = Modifier.align(Alignment.CenterVertically))}
}