防止键盘在Jetpack Compose应用程序中出现

8
我正在制作一个计算器来学习Compose,所以我在屏幕上放置了自己的数字按钮,并希望防止软键盘出现。
这是我的repo:https://github.com/vitor-ramos/CalculadorCompose 我注意到在TextFieldImpl.kt中有一个修饰符用于显示键盘,所以我尝试克隆代码并删除了这一行:keyboardController.value?.showSoftwareKeyboard()我知道复制代码不是一个好主意,但我想试一试,结果没成功。正如您在下面的原始代码中看到的那样,有一个TODO说它应该由BaseTextField处理,但是我查看了它的代码,没有找到它显示或隐藏键盘的位置。
val textFieldModifier = modifier
    .focusRequester(focusRequester)
    .focusObserver { isFocused = it.isFocused }
    .clickable(indication = null) {
        focusRequester.requestFocus()
        // TODO(b/163109449): Showing and hiding keyboard should be handled by BaseTextField.
        //  The requestFocus() call here should be enough to trigger the software keyboard.
        //  Investiate why this is needed here. If it is really needed, instead of doing
        //  this in the onClick callback, we should move this logic to the focusObserver
        //  so that it can show or hide the keyboard based on the focus state.
        keyboardController.value?.showSoftwareKeyboard()
    }

我在这个问题中发现,使用视图可以扩展EditText并更改功能,但我没有找到Compose的等效方法:Android: 禁用所有EditText上的软键盘
public class NoImeEditText extends EditText {
    public NoImeEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    public boolean onCheckIsTextEditor() {
        return false;
    }
}

我从未使用过Compose,但我非常感兴趣。我看了几个演讲,如果我理解得正确的话,那么使用NoImeEditText只是在自定义组合中使用@Composable方法的问题,对吗? - Fred
哦,我明白了,那是我的错。 - Fred
如果您不直接在TextField()中期望用户输入,为什么要使用它?是否可以用Text()替换TextField()? - Eric Cen
是的,我实际上尝试过那个,因为我认为它应该是一个简单的问题。 - Vitor Ramos
在Compose的问题跟踪器中有一个相关问题。发布时我会在这里更新。https://issuetracker.google.com/issues/169035120 - Vitor Ramos
显示剩余3条评论
5个回答

23

我已经测试了Arun Pdiyan的解决方案,在没有本地文本输入服务的情况下正常工作(在我的情况下,我从连接的条码阅读器读取数据)

 CompositionLocalProvider(
        LocalTextInputService provides null
    ) {
        TextField(
            value = barcodeReaderService.readedText.value,
            onValueChange = { textState.value=it },
            label = { Text("The Label") }
        )
    }

5
您可以通过为TextField提供TextInputService来隐藏compose上的键盘。 您可以实现自己的TextInputService,或仅将其传递为null以禁用输入服务。
CompositionLocalProvider(
  // You can also provides null to completely disable the default input service.
  LocalTextInputService provides myTextInputService 
) {
  BaseTextField(...)
}

关于这个问题,您可以在此处查看谷歌员工的答案:这里


请添加更多细节以扩展您的回答,例如工作代码或文档引用。 - Community

4

说明

我创建了一个组合式的 ReadonlyTextField,它在文本框前面放置了一个不可见的盒子。该盒子与文本框的大小相同。

通过这种解决方法,您无法再将焦点集中在文本框上,因此键盘不会出现。为了应用自定义点击处理,我在 Box-Modifier 中添加了 onClick

这并不是一个真正的干净的解决办法,但是是一个很好的解决方法。

ReadonlyTextField 的实现

@Composable
fun ReadonlyTextField(
    value: TextFieldValue,
    onValueChange: (TextFieldValue) -> Unit,
    modifier: Modifier = Modifier,
    onClick: () -> Unit,
    label: @Composable () -> Unit
) {

    Box {
        TextField(
            value = value,
            onValueChange = onValueChange,
            modifier = modifier,
            label = label
        )

        Box(
            modifier = Modifier
                .matchParentSize()
                .alpha(0f)
                .clickable(onClick = onClick),
        )
    }
}

只读文本框的用法

@Composable
fun App() {
    val textState = remember { mutableStateOf(TextFieldValue()) }

    Column {
        ReadonlyTextField(
            value = textState.value,
            onValueChange = { textState.value = it },
            onClick = {
                // custom click handling (e.g. open dialog)
            },
            label = {
                Text(text = "Keyboardless Input")
            }
        )
    }
}

我的medium博客中可以找到一个完整的集成示例: https://caelis.medium.com/jetpack-compose-datepicker-textfield-39808e42646a

同时,也要感谢这个stackoverflow答案: Jetpack Compose: Disable Interaction with TextField


前段时间我为此问题提出了一个问题,Compose团队回答我说他们正在改变整个焦点API,其中将包括一种不显示键盘或文本输入焦点的方法,但还是谢谢你的回答。 - Vitor Ramos

1
使用ReadonlyTextField无法定位光标。因此,在Compose AndroidView中添加了包装的EditText。
@Composable
fun NoKeyboardTextField(
    modifier: Modifier,
    text: String,
    textColor: Int
) {
    AndroidView(
        modifier = modifier,
        factory = { context ->
            AppCompatEditText(context).apply {
                isFocusable = true
                isFocusableInTouchMode = true
                showSoftInputOnFocus = false
            }
        },
        update = { view ->
            view.setText(text)
            view.setTextColor(textColor)
            view.setSelection(text.length)
        }
    )
}

0
修改您的TextField修饰符的焦点属性。
TextField(
    modifier = Modifier.focusProperties {
        canFocus = false
    },
    value = value,
    onValueChange = { text.value = it },
    label = { Text("Type") }
)

这个方法是有效的,但你需要在focusProperties中添加enter = { FocusRequester.Cancel },就像这样: TextField(modifier = Modifier.focusProperties { canFocus = false; enter = { FocusRequester.Cancel }}, ...) - user1185087

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