You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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、三星等主流设备上都表现一致
之前尝试方案失效原因
  • 方案1的clearAndSetSemantics会直接清空当前节点及子树的所有语义信息,自然会导致TalkBack完全跳过内容
  • 方案2的invisibleToUser()会直接告知无障碍服务当前节点及子树对用户不可见,同样会被TalkBack忽略
  • 方案3的空pointerInput仅拦截了触摸事件,但没有在语义层标记整个区域为禁用状态,TalkBack自然仍可以选中内部组件

内容的提问来源于stack exchange,提问作者Ersen Osman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 23:48:21