防止键盘出现在 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") }
)
}
我正在制作一个计算器来学习 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") }
)
}