如何在Jetpack Compose中显示键盘?

17

我怎样才能滑动键盘?我尝试过:

val keyboardController: SoftwareKeyboardController? = LocalSoftwareKeyboardController.current
  keyboardController?.show()

但它不起作用。我错过了什么?也许是一些清单标志吗?

7个回答

24
显示Compose中的键盘:

在Compose中显示键盘:

val showKeyboard = remember { mutableStateOf(true) }
val focusRequester = remember { FocusRequester() }
val keyboard = LocalSoftwareKeyboardController.current

OutlinedTextField(
    modifier = Modifier
            .fillMaxWidth()
            .focusRequester(focusRequester),
    value = value,
    textStyle = MaterialTheme.typography.body2,
    onValueChange = { onValueChange(it)},
    label = { Text(label) }
)

// LaunchedEffect prevents endless focus request
LaunchedEffect(focusRequester) {
    if (showKeyboard.equals(true)) {
        focusRequester.requestFocus()
        delay(100) // Make sure you have delay here
        keyboard?.show()
    }
}

7
当您打开对话框并希望对话框中的文本框自动获取焦点以及弹出键盘时,此代码无法正常工作。文本框获得了焦点,但键盘没有弹出。 - ino
1
@ino 请查看此处的对话框。只需将requestFocus()之前的延迟移动,或使用awaitFrame()即可。https://dev59.com/jlEG5IYBdhLWcg3wPXpF - rileyx
3
这里的showKeyboard.equals(true)总是返回false,因为equals()方法只会判断另一个对象是否“等于”它本身,而不是判断它们是否具有相同的值。请参见此处的示例 - https://www.educative.io/answers/what-is-objectsequals-in-java,取而代之的是使用if(showKeyboard.value)。 - Itay Feldman
如果 (showKeyboard.value) {... - Dan Alboteanu
无论如何,代码从未将showKeyboard.value设置为false。那么为什么还有这个变量呢? - Pointer Null
永远不要依赖延迟。awaitFrame()就足够了。 - undefined

11

delay 不是一个稳健的显示键盘的方法。在大多数情况下,键盘没有显示是因为窗口还没有获得焦点。解决方案如下:

val windowInfo = LocalWindowInfo.current
val focusRequester = remember { FocusRequester() }
TextField(modifier = Modifier.focusRequester(focusRequester)...)

LaunchedEffect(windowInfo) {
     snapshotFlow { windowInfo.isWindowFocused }.collect { isWindowFocused ->
         if (isWindowFocused) {
             focusRequester.requestFocus()
         }
     }
}

我们不应该将request focus作为副作用来使用吗? - VIVEK CHOUDHARY

4

我目前正在使用的是组合BOM版本2023.05.01

其他答案对我没有用。然而,当我改变了已接受答案中的LaunchedEffect时,我成功让它工作了。使用以下代码片段,软键盘会打开,你可以在文本框内开始输入。

val focusRequester = remember { FocusRequester() }

OutlinedTextField(
    modifier = Modifier
            .fillMaxWidth()
            .focusRequester(focusRequester),
    value = value,
    textStyle = MaterialTheme.typography.body2,
    onValueChange = { onValueChange(it)},
    label = { Text(label) }
)

LaunchedEffect(focusRequester) {
   awaitFrame()
   focusRequester.requestFocus()
}

2
根据我的使用情况,当底部工作表与editText一起显示时,我需要显示键盘。 接受的答案第一次有效,然后如果用户暂停去其他应用程序,就会停止工作。 因此,我将上述解决方案与生命周期事件结合使用,以在视图实际可见给用户时触发键盘。
fun SomeView(lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current) {
 val focusRequester = remember { FocusRequester() }
 val keyboard = LocalSoftwareKeyboardController.current
 val scope = rememberCoroutineScope()


 DisposableEffect(key1 = lifecycleOwner, effect = {

       val observer = LifecycleEventObserver { _, event ->

           scope.launch {
               if (event == Lifecycle.Event.ON_RESUME) {
                   focusRequester.requestFocus()
                   awaitFrame()
                   keyboard?.show()
               }
           }
       }

       // Add the observer to the lifecycle
       lifecycleOwner.lifecycle.addObserver(observer)

       onDispose {
           lifecycleOwner.lifecycle.removeObserver(observer)
       }
   })


         TextField(
            modifier = Modifier
                .fillMaxWidth()
                .focusRequester(focusRequester),
            value = "",
            onValueChange = {},
            placeholder = { Text(text = "New Note") },
            colors = TextFieldDefaults.textFieldColors(
                backgroundColor = Color.Transparent,
            )
        )

上面的代码添加了一个生命周期观察者,并在生命周期事件为ON_RESUME时触发键盘显示。

0
当需要在打开场景时显示键盘以进行编辑时,以下方法运行良好:
    val focusRequester = remember { FocusRequester() }
    LaunchedEffect(Unit) { focusRequester.requestFocus() }

    TextField(
        ...
        modifier = Modifier
           .fillMaxWidth()
           .focusRequester(focusRequester),
    )

-2

Leon Wu的回答https://dev59.com/11EG5IYBdhLWcg3wLFsk#75985103似乎是最好的。对于我的用例,将请求重点放在副作用中更好。

val focusRequester = remember {
    FocusRequester()
}
var queryText by remember(query) { mutableStateOf(query) }

val scope = rememberCoroutineScope()
val windowInfo = LocalWindowInfo.current

SideEffect {
    scope.launch {
        snapshotFlow { windowInfo.isWindowFocused }.collect { isWindowFocused ->
            if (isWindowFocused && requestFocus) {
                focusRequester.requestFocus()
            }
        }
    }
}
TextField(modifier = Modifier.focusRequester(focusRequester)...)

你的回答无法编译。 - J. Doe
@J.Doe 这段代码我也可以编译通过。 - VIVEK CHOUDHARY
胡言乱语,您正在引用一个未在任何地方定义的变量“query”。 - J. Doe
答案不在于如何使用查询,而在于如何显示键盘。这只是代码片段,不是整个代码。 - VIVEK CHOUDHARY
毫无意义,添加不相关的、无法编译的代码片段有何意义呢?这没有任何意义。 - J. Doe

-10

官方方法有什么问题?

fun showSoftKeyboard(view: View) {
    if (view.requestFocus()) {
        val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
    }
}

阅读更多此处

如果您只是这样使用,这种方法就有效:

showSoftKeyboard(AndroidView(context))

您也可以尝试通过将AndroidView放置在函数体中来完全消除参数。


这个方法可行,但由于我只使用Jetpack Compose,我不喜欢show-Method中的视图。 - Ralf Wickum
没什么问题,只需将一个 AndroidView Composable 传递给它,它就会处理。你可以为此创建一个空的 AndroidView。这似乎非常简单,所以我认为它是理想的。 - Richard Onslow Roper
请勿在回答中包含元评论。这不是适当的地方。如果您想问这种方法有什么问题,请提出一个新问题。如果您想知道如何改进这个问题,可以在 Meta 上提问。询问读者哪里出了问题是不合适的。 - Dharman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接