Compose UI
Compose 底层 · androidx.compose.ui
输入、手势与语义1.13.0-alpha01
pointerInput 处理原始手势,semantics 让操作可访问且可测试。
最后更新 2026-08-01
优先使用高层交互
按钮、clickable、toggleable 已经组合了点击、键盘、焦点、语义和视觉 indication。只有需要自定义手势竞争或原始指针数据时才进入 pointerInput。
Modifier.pointerInput(Unit) {
detectTapGestures(
onLongPress = { position -> showMenu(position) },
)
}常用手势检测器
| 检测器 | 用途 |
|---|---|
detectTapGestures | 点击/双击/长按 |
detectDragGestures | 拖拽(onDragStart/onDrag/onDragEnd) |
detectTransformGestures | 捏合缩放/旋转/平移 |
awaitPointerEventScope | 原始指针事件循环 |
Modifier.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consume()
offset += dragAmount
}
}key 改变时 pointer input handler 会取消并重启。handler 内应遵守协程取消,不能把阻塞操作放在事件循环里。
手势能用不代表辅助技术能用
纯 pointerInput 不会自动声明”这是按钮”。自定义操作必须补齐语义,或更好地从已有高层 modifier 组合:
复制即用
Modifier.semantics {
contentDescription = "播放"
role = Role.Button
onClick {
play()
true
}
}语义规范
- 语义树是 Compose UI 测试定位和断言的基础。
- 不要给已有 Text 再重复设置相同 contentDescription,否则屏幕阅读器可能朗读两遍。
- 自定义可点击元素记得
role+onClick,否则 TalkBack 不识别。
常见陷阱
- 纯 pointerInput 没语义:辅助技术/测试找不到节点。
- 重复 contentDescription:屏幕阅读器朗读两遍。
- 阻塞事件循环:pointerInput 内做阻塞操作,手势会卡。
- 忘 consume 事件:
change.consume()不调用,手势会传递到父级。
要点
- 高层交互(clickable/toggleable)已含语义,优先使用。
- 自定义手势才进 pointerInput;key 变则重启。
- 自定义操作必须补齐 semantics(role + onClick)。
- 语义树也是 UI 测试定位基础。