Jetpack compose: Setting ImeAction does not close or change focus for the keyboard

Mah*_*alv 9 android android-jetpack-compose

I'm using Jetpack compose 1.0.0-alpha07. I made a login screen that contains two TextFields customized using other composables.

However, setting ImeAction in keyboardOptions does not seem to work. For instance ImeAction.Next does not move focus to the next TextField. I think I should do something to make it possible, but no document or article has talked even briefly about ImeOptions. Here's the code I have for the screen:

Login composable:

EmailEdit(onChange = { email.value = it })
PasswordEdit(onChange = { password.value = it })
Run Code Online (Sandbox Code Playgroud)

EmailEdit:

@Composable
fun EmailEdit(onChange: (String) -> Unit) {
    val t = remember { mutableStateOf("") }
    TextField(
        value = t.value,
        onValueChange = { value ->
            t.value = value
            onChange(value)
        },
        leadingIcon = { Icon(asset = Icons.Default.Email) },
        label = { Text(text = "Email") },
        maxLines = 1,
        keyboardOptions = KeyboardOptions(
            imeAction = ImeAction.Next, // ** Go to next **
            keyboardType = KeyboardType.Email
        ),
        visualTransformation = VisualTransformation.None
    )
}      errorHint = "Not a valid email"
    )
}
Run Code Online (Sandbox Code Playgroud)

PassEdit:

@Composable
fun PasswordEdit(onChange: (String) -> Unit) {
    val t = remember { mutableStateOf("") }
    TextField(
        value = t.value,
        onValueChange = { value ->
            t.value = value
            onChange(value)
        },
        leadingIcon = { Icon(asset = Icons.Default.Security) },
        label = { Text(text = "Password") },
        maxLines = 1,
        keyboardOptions = KeyboardOptions(
            imeAction = ImeAction.Done, // ** Done. Close the keyboard **
            keyboardType = KeyboardType.Text
        ),
        visualTransformation = PasswordVisualTransformation()
    )
}
Run Code Online (Sandbox Code Playgroud)

To perform Done and Next what code should I add?

Jat*_*eva 28

您可以使用LocalFocusManager

val localFocusManager = LocalFocusManager.current
Run Code Online (Sandbox Code Playgroud)

在您的字段的父级可组合项内。

要将焦点移至下一个字段:

localFocusManager.moveFocus(FocusDirection.Down)
Run Code Online (Sandbox Code Playgroud)

在 KeyboardActions 的 onNext 内部将焦点向左、右、上、下等特定方向移动。

明确焦点:

localFocusManager.clearFocus()
Run Code Online (Sandbox Code Playgroud)

在KeyboardActionsonDone内部以清除焦点。

电子邮件字段:

OutlinedTextField(
            value = userId,
            onValueChange = { userId = it },
            label = { Text("Email") },
            modifier = Modifier.fillMaxWidth(),
            singleLine = true,
            leadingIcon = {
                Icon(
                    painter = painterResource(id = R.drawable.ic_account),
                    contentDescription = "ID"
                )
            },
            colors = TextFieldDefaults.outlinedTextFieldColors(
                focusedBorderColor = Color.Gray,
                unfocusedBorderColor = Color.LightGray,
                focusedLabelColor = Color(0xffcc0000)
            ),
            keyboardOptions =
            KeyboardOptions(
                keyboardType = KeyboardType.Text,
                imeAction = ImeAction.Next
            ),
            keyboardActions = KeyboardActions(onNext = {
                localFocusManager.moveFocus(FocusDirection.Down)
            })
        )
Run Code Online (Sandbox Code Playgroud)

密码字段:

OutlinedTextField(
            value = password,
            onValueChange = { password = it },
            label = { Text("Password") },
            modifier = Modifier.fillMaxWidth(),
            singleLine = true,
            leadingIcon = {
                Icon(
                    painter = painterResource(id = R.drawable.ic_password),
                    contentDescription = "Password"
                )
            },
            colors = TextFieldDefaults.outlinedTextFieldColors(
                focusedBorderColor = Color.Gray,
                unfocusedBorderColor = Color.LightGray,
                focusedLabelColor = Color(0xffcc0000)
            ),
            keyboardOptions =
            KeyboardOptions(
                keyboardType = KeyboardType.Password,
                imeAction = ImeAction.Done
            ),
            keyboardActions = KeyboardActions(onDone = {
                localFocusManager.clearFocus()
            })

        )
Run Code Online (Sandbox Code Playgroud)

尝试过版本1.0.1

  • 这有效。但当字段不可见时,例如在键盘后面,则不会。 (3认同)

Gab*_*tti 15

有了1.0.x您可以使用

  • keyboardOptions:包含配置的软件键盘选项,例如KeyboardTypeImeAction
  • keyboardActions 当输入服务发出 IME 动作时,会调用相应的回调

对于Done

您可以使用LocalSoftwareKeyboardController与键盘进行交互。

keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(
    onDone = {keyboardController?.hide()}
)
Run Code Online (Sandbox Code Playgroud)

对于Next

keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(
    onNext = { focusRequester.requestFocus() }
)
Run Code Online (Sandbox Code Playgroud)

就像是:

val (focusRequester) = FocusRequester.createRefs()
val keyboardController = LocalSoftwareKeyboardController.current

TextField(
    value = text,
    onValueChange = {
        text = it
    },
    label = { Text("Label") },
    keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
    keyboardActions = KeyboardActions(
        onNext = { focusRequester.requestFocus() } 
    )
)

TextField(
    value = text,
    onValueChange = {
        text = it
    },
    modifier = Modifier.focusRequester(focusRequester),
    label = { Text("Label") },
    keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
    keyboardActions = KeyboardActions(
        onDone = { keyboardController?.hide() }
    )
)
Run Code Online (Sandbox Code Playgroud)

  • 添加 Modifier.focusRequester(focusRequester) 解决 IllegalStateException (3认同)
  • 对于 Compose 1.1.1,似乎不再需要“keyboardActions”和手动焦点管理。`KeyboardOptions(imeAction = ImeAction.Next)` 足以获得正确的行为。 (3认同)
  • 奇怪的是,当我尝试以这种方式请求焦点时遇到异常:`java.lang.IllegalStateException:FocusRequester 未初始化。原因之一是您在构图期间请求焦点变化。焦点请求不应在合成过程中提出,而应在响应某些事件时提出。 (2认同)
  • 奇怪的是,在横向模式下按 onNext 时键盘会关闭,而在纵向模式下则工作正常。 (2认同)

Noa*_*oah 11

使用onImeActionPerformed参数。

对于Done

TextField(
    onImeActionPerformed = { _, controller ->
        controller?.hideSoftwareKeyboard()
    }
)
Run Code Online (Sandbox Code Playgroud)

对于Next

val focusRequester = remember { FocusRequester() }
TextField(
    onImeActionPerformed = { _, _ ->
        focusRequester.requestFocus()
    }
)
TextField(
    modifier = Mofifier.focusRequester(focusRequester)
)
Run Code Online (Sandbox Code Playgroud)

这是一个工作示例:

val focusRequester = remember { FocusRequester() }
val email = remember { mutableStateOf("") }
TextField(
    value = email.value,
    onValueChange = { email.value = it },
    imeAction = ImeAction.Next,
   onImeActionPerformed = { _, _ -> focusRequester.requestFocus() }
)
val password = remember { mutableStateOf("") }
TextField(
    value = password.value,
    onValueChange = { password.value = it },
    imeAction = ImeAction.Done,
    onImeActionPerformed = { _, controller -> controller?.hideSoftwareKeyboard() },
    modifier = Modifier.focusRequester(focusRequester)
)
Run Code Online (Sandbox Code Playgroud)

文档:

  • 如果我们有两个以上的文本字段怎么办?下一步如何聚焦? (2认同)

alf*_*tap 7

在本例中,使用 Compose 时,您需要为屏幕上的每个可聚焦文本字段创建一组引用,如下所示(textField1、textField2),并获取对 KeyboardController 的引用。

然后,您可以向键盘选项添加一种操作类型,指示显示键盘时操作按钮的外观。

在 KeyboardActions 参数中,您可以在指定的 IME 操作上调用函数 - 在本例中,我已经声明我希望 textField2 在按下键盘操作按钮时获得焦点。您可以在 TextField 的 Modifier.focusRequester 参数中分配引用。

最后,为了使您的第一个 TextField 在屏幕出现时获得焦点,您可以调用 DisposableEffect 函数,在其中指定您希望 textField1 在屏幕首次显示时获得焦点。

val (textField1, textField2) = remember { FocusRequester.createRefs() }
val keyboardController = LocalSoftwareKeyboardController.current

TextField(
    modifier = Modifier.focusRequester(textField1),
    keyboardOptions  = KeyboardOptions(imeAction = ImeAction.Next),
    keyboardActions = KeyboardActions( onNext = {textField2.requestFocus()}
   ),
)


 TextField(
    modifier = Modifier.focusRequester(textField2),
    keyboardOptions  = KeyboardOptions(imeAction = ImeAction.Done),
    keyboardActions = KeyboardActions( onDone = { 
    keyboardController?.hide()}
   ),
)

DisposableEffect(Unit) {
    textField1.requestFocus()
    onDispose { }
}
Run Code Online (Sandbox Code Playgroud)