Jetpack Compose如何获取其他Composable语义实现禁用组件适配
问题根因
之前实现的兼容问题本质是Compose语义树的合并逻辑冲突:额外叠加的拦截层哪怕设置了clickable(enabled = false),也会作为独立的交互语义节点存在,和内部内容的语义节点产生合并冲突,不同厂商定制的TalkBack对冲突语义的处理逻辑不一致,最终出现部分设备读不出文本、部分设备识别不到自定义语义属性的问题。
可行实现方案
不需要手动提取内部content的语义信息,也不需要额外传入自定义描述,只要去掉冗余的覆盖拦截层,直接在内容容器上同时处理视觉效果、事件拦截、语义标记即可,完整实现代码如下:
@Composable fun DisableOverlay( enabled: Boolean, alpha: Float = 0.45F, content: @Composable () -> Unit ) { if (enabled) { content() return } Box( modifier = Modifier .wrapContentWidth() .wrapContentHeight() .alpha(alpha) // 合并所有子节点语义,自动收集内部文本、自定义contentDescription .semantics(mergeDescendants = true) { // 明确标记整个子树为禁用状态,TalkBack不会单独选中内部组件 disabled = true } // 拦截所有触摸事件,不向下传递 .pointerInput(Unit) { awaitPointerEventScope { while (true) { awaitPointerEvent().changes.forEach { it.consume() } } } } ) { content() } }
方案效果说明
- 视觉上和原实现一致,禁用时自动给内部内容加透明度置灰
- 普通触摸事件会被完全拦截,不会传递到内部可组合项
- 无障碍适配完全符合系统规范:
- 自动合并内部所有子节点的语义信息,不需要手动传入contentDescription,Text文本、子组件自定义的
contentDescription都会被TalkBack正常朗读 - 语义层明确标记
disabled = true后,TalkBack不会单独选中内部的子组件,朗读时还会自动追加系统默认的“已停用”提示,在Pixel、三星等主流设备上都表现一致
- 自动合并内部所有子节点的语义信息,不需要手动传入contentDescription,Text文本、子组件自定义的
之前尝试方案失效原因
- 方案1的
clearAndSetSemantics会直接清空当前节点及子树的所有语义信息,自然会导致TalkBack完全跳过内容 - 方案2的
invisibleToUser()会直接告知无障碍服务当前节点及子树对用户不可见,同样会被TalkBack忽略 - 方案3的空
pointerInput仅拦截了触摸事件,但没有在语义层标记整个区域为禁用状态,TalkBack自然仍可以选中内部组件
内容的提问来源于stack exchange,提问作者Ersen Osman
相关产品推荐
相关产品推荐

