在 Jetpack Compose 中设置焦点顺序的最简单方法是什么?
What is the simplest way to set the focus order in Jetpack Compose?
我有一列 TextFields,类似于:
Column {
TextField(
value = ...,
onValueChange = { ... },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.next),
)
TextField(
value = ...,
onValueChange = { ... },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.next),
)
.
.
.
}
当用户按下 Tab 键或键盘上的下一个按钮时,我希望将每个 TextField 的焦点移动到下一个。当前按下 Tab 会将一个选项卡插入到 TextField 中。按下一步按钮什么都不做。我可以为每个 TextField 创建一个 FocusRequester 并设置 keyboardActions onNext 以请求将焦点放在每个文本字段的下一个字段上。这有点乏味,并且没有解决 Tab 行为。
不确定这是否是更简单的方法,但您可以为每个字段创建一个 FocusRequester
对象并按照您想要的顺序请求焦点。
@Composable
fun FocusRequestScreen() {
// Create FocusRequesters... (you can use createRefs function)
val focusRequesters = List(3) { FocusRequester() }
Column {
TextFieldWithFocusRequesters(focusRequesters[0], focusRequesters[1])
TextFieldWithFocusRequesters(focusRequesters[1], focusRequesters[2])
TextFieldWithFocusRequesters(focusRequesters[2], focusRequesters[0])
}
}
@Composable
private fun TextFieldWithFocusRequesters(
focusRequester: FocusRequester,
nextFocusRequester: FocusRequester
) {
var state by rememberSaveable {
mutableStateOf("Focus Transition Test")
}
TextField(
value = state,
onValueChange = { text -> state = text },
// Here it is what you want...
modifier = Modifier
.focusOrder(focusRequester) {
nextFocusRequester.requestFocus()
}
,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next)
)
}
我从 here 获得此代码。它并没有解决选项卡问题...... :(
关于顺序可以查看.
要使用 Tab 键,您可以使用 onKeyEvent
modifier。
TextField(
modifier = Modifier
.focusRequester(focusRequester)
.onKeyEvent {
if (it.key.keyCode == Key.Tab.keyCode){
focusRequesterNext.requestFocus()
true //true -> consumed
} else false },
value = text,
onValueChange = { it -> text = it },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(
onNext = {focusRequesterNext.requestFocus()}
)
)
我最近找到了这篇文章:https://medium.com/google-developer-experts/focus-in-jetpack-compose-6584252257fe
它解释了一种处理焦点的不同方法,这种方法要简单得多。
val focusManager = LocalFocusManager.current
TextField(
modifier = Modifier
.onPreviewKeyEvent {
if (it.key == Key.Tab && it.nativeKeyEvent.action == ACTION_DOWN){
focusManager.moveFocus(FocusDirection.Down)
true
} else {
false
}
},
value = text,
onValueChange = { it -> text = it },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Down) }
)
)
我目前在 compose_version = '1.0.2'
。
当您按下一个按钮时,焦点不会移动,因为尽管 the default keyboard action is to move focus to the next one,compose 似乎不知道下一个应该是哪一个。为每个项目创建 FocusRequester
并通过 Modifier.focusOrder() {}
设置它们的焦点顺序可以工作(顺便说一句,如果您选择,则无需设置 keyboardActions
的 onNext
来请求焦点这样),但是由于您的 TextField
在同一个 Column
中,您可以设置 keyboardActions
告诉 compose 将焦点移动到向下方向的那个。类似于:
Column {
val focusManager = LocalFocusManager.current
TextField(
value = "", onValueChange = {},
keyboardOptions = KeyboardOptions( imeAction = ImeAction.Next ),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Down) }
)
)
TextField(
value = "", onValueChange = {},
keyboardOptions = KeyboardOptions( imeAction = ImeAction.Next ),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Down) }
)
)
TextField(
value = "", onValueChange = {},
keyboardOptions = KeyboardOptions( imeAction = ImeAction.Next ),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Down) }
)
)
}
执行此操作后,IME 键盘上的下一个按钮应该可以使用。
对于 Tab 键,因为 TextField
不会自动处理 Tab 键,所以你可能想要在 Modifier.onKeyEvent{}
中使用 focusManager
以与上述示例相同的方式移动焦点。
设置单线,请尝试
OutlinedTextField(
...
singleLine = true,
)
简单示例
@Composable
fun Test() {
val focusManager = LocalFocusManager.current
var text1 by remember {
mutableStateOf("")
}
var text2 by remember {
mutableStateOf("")
}
Column() {
OutlinedTextField(value = text1, onValueChange = {
text1 = it
},
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
keyboardType = KeyboardType.Text
),
keyboardActions = KeyboardActions(
onNext ={
focusManager.moveFocus(FocusDirection.Down)
}
),
singleLine = true
)
OutlinedTextField(value = text2, onValueChange = {
text2 = it
},
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
keyboardType = KeyboardType.Text
),
keyboardActions = KeyboardActions(
onNext ={
focusManager.moveFocus(FocusDirection.Down)
}
),
singleLine = true
)
}
}
我有一列 TextFields,类似于:
Column {
TextField(
value = ...,
onValueChange = { ... },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.next),
)
TextField(
value = ...,
onValueChange = { ... },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.next),
)
.
.
.
}
当用户按下 Tab 键或键盘上的下一个按钮时,我希望将每个 TextField 的焦点移动到下一个。当前按下 Tab 会将一个选项卡插入到 TextField 中。按下一步按钮什么都不做。我可以为每个 TextField 创建一个 FocusRequester 并设置 keyboardActions onNext 以请求将焦点放在每个文本字段的下一个字段上。这有点乏味,并且没有解决 Tab 行为。
不确定这是否是更简单的方法,但您可以为每个字段创建一个 FocusRequester
对象并按照您想要的顺序请求焦点。
@Composable
fun FocusRequestScreen() {
// Create FocusRequesters... (you can use createRefs function)
val focusRequesters = List(3) { FocusRequester() }
Column {
TextFieldWithFocusRequesters(focusRequesters[0], focusRequesters[1])
TextFieldWithFocusRequesters(focusRequesters[1], focusRequesters[2])
TextFieldWithFocusRequesters(focusRequesters[2], focusRequesters[0])
}
}
@Composable
private fun TextFieldWithFocusRequesters(
focusRequester: FocusRequester,
nextFocusRequester: FocusRequester
) {
var state by rememberSaveable {
mutableStateOf("Focus Transition Test")
}
TextField(
value = state,
onValueChange = { text -> state = text },
// Here it is what you want...
modifier = Modifier
.focusOrder(focusRequester) {
nextFocusRequester.requestFocus()
}
,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next)
)
}
我从 here 获得此代码。它并没有解决选项卡问题...... :(
关于顺序可以查看
要使用 Tab 键,您可以使用 onKeyEvent
modifier。
TextField(
modifier = Modifier
.focusRequester(focusRequester)
.onKeyEvent {
if (it.key.keyCode == Key.Tab.keyCode){
focusRequesterNext.requestFocus()
true //true -> consumed
} else false },
value = text,
onValueChange = { it -> text = it },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(
onNext = {focusRequesterNext.requestFocus()}
)
)
我最近找到了这篇文章:https://medium.com/google-developer-experts/focus-in-jetpack-compose-6584252257fe
它解释了一种处理焦点的不同方法,这种方法要简单得多。
val focusManager = LocalFocusManager.current
TextField(
modifier = Modifier
.onPreviewKeyEvent {
if (it.key == Key.Tab && it.nativeKeyEvent.action == ACTION_DOWN){
focusManager.moveFocus(FocusDirection.Down)
true
} else {
false
}
},
value = text,
onValueChange = { it -> text = it },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Down) }
)
)
我目前在 compose_version = '1.0.2'
。
当您按下一个按钮时,焦点不会移动,因为尽管 the default keyboard action is to move focus to the next one,compose 似乎不知道下一个应该是哪一个。为每个项目创建 FocusRequester
并通过 Modifier.focusOrder() {}
设置它们的焦点顺序可以工作(顺便说一句,如果您选择,则无需设置 keyboardActions
的 onNext
来请求焦点这样),但是由于您的 TextField
在同一个 Column
中,您可以设置 keyboardActions
告诉 compose 将焦点移动到向下方向的那个。类似于:
Column {
val focusManager = LocalFocusManager.current
TextField(
value = "", onValueChange = {},
keyboardOptions = KeyboardOptions( imeAction = ImeAction.Next ),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Down) }
)
)
TextField(
value = "", onValueChange = {},
keyboardOptions = KeyboardOptions( imeAction = ImeAction.Next ),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Down) }
)
)
TextField(
value = "", onValueChange = {},
keyboardOptions = KeyboardOptions( imeAction = ImeAction.Next ),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Down) }
)
)
}
执行此操作后,IME 键盘上的下一个按钮应该可以使用。
对于 Tab 键,因为 TextField
不会自动处理 Tab 键,所以你可能想要在 Modifier.onKeyEvent{}
中使用 focusManager
以与上述示例相同的方式移动焦点。
设置单线,请尝试
OutlinedTextField(
...
singleLine = true,
)
简单示例
@Composable
fun Test() {
val focusManager = LocalFocusManager.current
var text1 by remember {
mutableStateOf("")
}
var text2 by remember {
mutableStateOf("")
}
Column() {
OutlinedTextField(value = text1, onValueChange = {
text1 = it
},
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
keyboardType = KeyboardType.Text
),
keyboardActions = KeyboardActions(
onNext ={
focusManager.moveFocus(FocusDirection.Down)
}
),
singleLine = true
)
OutlinedTextField(value = text2, onValueChange = {
text2 = it
},
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
keyboardType = KeyboardType.Text
),
keyboardActions = KeyboardActions(
onNext ={
focusManager.moveFocus(FocusDirection.Down)
}
),
singleLine = true
)
}
}