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

Prevent the keyboard from appearing in a Jetpack Compose app

我正在制作一个计算器来学习 Compose,所以我在屏幕上放置了自己的数字按钮,我想防止出现软键盘。

这是我的回购协议: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: Disable soft keyboard at all EditTexts

public class NoImeEditText extends EditText {
    public NoImeEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    public boolean onCheckIsTextEditor() {
        return false;
    }
}

说明

我创建了一个可组合项 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),
        )
    }
}

ReadonlyTextField 的用法

@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")
            }
        )
    }
}

完整的集成示例可以在我的媒体中找到post: https://caelis.medium.com/jetpack-compose-datepicker-textfield-39808e42646a

学分也转到这个 Whosebug 答案:

使用 ReadonlyTextField 无法定位光标。所以在 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)
        }
    )
}

您可以通过向 TextField 提供 TextInputService 来在撰写时隐藏键盘。您可以实现您的 TextInputService 或将其传递为 null 以禁用输入服务。

CompositionLocalProvider(
  // You can also provides null to completely disable the default input service.
  LocalTextInputService provides myTextInputService 
) {
  BaseTextField(...)
}

您可能会看到 google 名员工关于此主题的回答 here

我已经测试了 Arun Pdiyan 解决方案,并且在使用 null LocalTextInputService 时非常有效(在我的例子中,我从设备附加条码读取数据 reader)

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