在 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() {} 设置它们的焦点顺序可以工作(顺便说一句,如果您选择,则无需设置 keyboardActionsonNext 来请求焦点这样),但是由于您的 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
        )
    }
}