跳到主要内容

控制焦点与硬件按键

移动和清除焦点​

使用 remember 保持每个 FocusRequester 稳定,将其附加到目标,并在来源上声明方向遍历。 使用 LocalFocusManager.current 执行当前 Session 范围的移动或清除操作。调用 requestFocus() 之前,requester 必须已附加到已挂载的目标。

fun UiTreeBuilder.CredentialFocusForm() {
val email = rememberTextFieldState()
val password = rememberTextFieldState()
val passwordFocus = remember { FocusRequester() }
val focusManager = LocalFocusManager.current

Column(
modifier = Modifier
.focusGroup()
.onPreviewKeyEvent { event ->
if (event.key == Key.Escape && event.type == KeyEventType.KeyDown) {
focusManager.clearFocus(force = true)
true
} else {
false
}
},
) {
TextField(
state = email,
label = "Email",
modifier = Modifier.focusProperties {
next = passwordFocus
down = passwordFocus
},
)
TextField(
state = password,
label = "Password",
modifier = Modifier.focusRequester(passwordFocus),
)
Button(
text = "Focus password",
onClick = { passwordFocus.requestFocus() },
)
}
}

onPreviewKeyEvent 从最外层声明式祖先传播到焦点目标。未消费事件随后通过 onKeyEvent 从目标向上冒泡。硬件按键与软键盘组合输入相互独立;后者继续通过 TextFieldState 和 Android 输入桥接运行。

恢复带 key 的子项​

临时移除或回收焦点组之前调用 saveFocusedChild(),返回后再调用 restoreFocusedChild()。恢复使用声明式节点 key;在匹配目标挂载之前会一直保持待处理。 页面或进程恢复仍由应用状态负责,并在挂载后显式请求焦点。

保持 Pager 编辑器可见​

垂直滚动所有者通过 Android 原生子矩形链显示焦点编辑器,即使直接用户滚动已禁用也一样。 Pager 拥有整页选择,因此应把可能被遮挡的表单放入页面自己的 ScrollableColumn;外层 VerticalPager 继续由应用页面状态控制。不存在焦点跟随开关。通过决定哪个编辑器接收焦点 来控制不希望出现的初始移动;不要关闭滚动所有者的可见性契约。所有权、传播和 Android 映射见 Modifier 架构。