Jetpack Compose on Wear 中的 BasicTextField 问题 OS
Problem with BasicTextField in Jetpack Compose on Wear OS
我是 Compose 新手,在 Wear OS 上输入文本字段时遇到问题。
问题是我无法像通常在 Android 上那样使用软键盘。此外,当我尝试在 XML 中实现相同的布局时 - 它起作用了。
因此,当我点击输入文本字段时,键盘会弹出然后隐藏。当我再次点击时 - 键盘弹出并保持打开状态,但如果我尝试输入任何文本 - 输入字段(键盘本身)中没有任何内容,尽管输入的文本正在传递到 UI 上的输入文本字段.
这是我在点击输入文本字段打开键盘时在模拟器日志中得到的内容:
2021-11-24 09:44:36.569 W/IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection
2021-11-24 09:44:36.571 W/IInputConnectionWrapper: getTextAfterCursor on inactive InputConnection
2021-11-24 09:44:36.649 W/RecordingIC: requestCursorUpdates is not supported
这是我在真实设备上得到的:
2021-11-24 09:35:39.783 W/IInputConnectionWrapper: getExtractedText on inactive InputConnection
2021-11-24 09:35:39.872 W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: setComposingRegion on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: getExtractedText on inactive InputConnection
2021-11-24 09:35:39.882 W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
2021-11-24 09:35:39.883 W/IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection
2021-11-24 09:35:39.884 W/IInputConnectionWrapper: getTextAfterCursor on inactive InputConnection
2021-11-24 09:35:39.888 W/IInputConnectionWrapper: getSelectedText on inactive InputConnection
2021-11-24 09:35:39.890 W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
2021-11-24 09:35:39.891 W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
2021-11-24 09:35:39.891 W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
2021-11-24 09:35:39.891 W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
2021-11-24 09:35:39.891 W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
这是我的 'composable':
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun ActivationScreen() {
var key by remember { mutableStateOf("") }
var isReady by remember {
mutableStateOf(false)
}
Column(modifier = Modifier
.padding(40.dp)
.fillMaxSize()
) {
val keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = FocusRequester()
BasicTextField(
value = key,
onValueChange = {
//isReady = it.length>11
key = it
},
singleLine = true,
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = {
keyboardController?.hide()
}
),
modifier = Modifier
.size(140.dp, 20.dp)
.background(Color.White)
.align(Alignment.CenterHorizontally)
//.focusRequester(focusRequester)
//.focusOrder(focusRequester)
)
Text(
text = "ACTIVATION",
)
val status = if (isReady) "READY" else "NOT READY"
Text(
text = status,
)
}
}
你应该避免在 Wear 上输入文字,但如果你真的需要它,GBboard activity 是最好的激活方式。
@Composable
fun TextInput() {
val label = remember { mutableStateOf("Start")}
val launcher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
it.data?.let { data ->
val results: Bundle = RemoteInput.getResultsFromIntent(data)
val ipAddress: CharSequence? = results.getCharSequence("ip_address")
label.value = ipAddress as String
}
}
Column() {
Spacer(modifier = Modifier.height(20.dp))
Chip(
label = { Text(label.value) },
onClick = {}
)
Chip(
label = { Text("Search with specific IP") },
onClick = {
val intent: Intent = RemoteInputIntentHelper.createActionRemoteInputIntent();
val remoteInputs: List<RemoteInput> = listOf(
RemoteInput.Builder("ip_address")
.setLabel("Manual IP Entry")
.wearableExtender {
setEmojisAllowed(false)
setInputActionType(EditorInfo.IME_ACTION_DONE)
}.build()
)
RemoteInputIntentHelper.putRemoteInputsExtra(intent, remoteInputs)
launcher.launch(intent)
}
)
}
}
根据@Yuri Schimke 的回答,这是一个接受占位符、值和 onChange 作为属性的通用组件实现。
import android.app.RemoteInput
import android.content.Intent
import android.os.Bundle
import android.view.inputmethod.EditorInfo
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.Text
import androidx.wear.input.RemoteInputIntentHelper
import androidx.wear.input.wearableExtender
@Composable
fun TextInput(
placeholder: String,
value: String?,
onChange: (value: String) -> Unit,
) {
val launcher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
it.data?.let { data ->
val results: Bundle = RemoteInput.getResultsFromIntent(data)
val newValue: CharSequence? = results.getCharSequence(placeholder)
onChange(newValue as String)
}
}
Column() {
Chip(
label = { Text(if (value == null || value.isEmpty()) placeholder else value) },
onClick = {
val intent: Intent = RemoteInputIntentHelper.createActionRemoteInputIntent();
val remoteInputs: List<RemoteInput> = listOf(
RemoteInput.Builder(placeholder)
.setLabel(placeholder)
.wearableExtender {
setEmojisAllowed(false)
setInputActionType(EditorInfo.IME_ACTION_DONE)
}.build()
)
RemoteInputIntentHelper.putRemoteInputsExtra(intent, remoteInputs)
launcher.launch(intent)
}
)
}
}
注意:这需要androidx.wear:wear-input:1.2.0+
我是 Compose 新手,在 Wear OS 上输入文本字段时遇到问题。 问题是我无法像通常在 Android 上那样使用软键盘。此外,当我尝试在 XML 中实现相同的布局时 - 它起作用了。 因此,当我点击输入文本字段时,键盘会弹出然后隐藏。当我再次点击时 - 键盘弹出并保持打开状态,但如果我尝试输入任何文本 - 输入字段(键盘本身)中没有任何内容,尽管输入的文本正在传递到 UI 上的输入文本字段.
这是我在点击输入文本字段打开键盘时在模拟器日志中得到的内容:
2021-11-24 09:44:36.569 W/IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection
2021-11-24 09:44:36.571 W/IInputConnectionWrapper: getTextAfterCursor on inactive InputConnection
2021-11-24 09:44:36.649 W/RecordingIC: requestCursorUpdates is not supported
这是我在真实设备上得到的:
2021-11-24 09:35:39.783 W/IInputConnectionWrapper: getExtractedText on inactive InputConnection
2021-11-24 09:35:39.872 W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: setComposingRegion on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
2021-11-24 09:35:39.873 W/IInputConnectionWrapper: getExtractedText on inactive InputConnection
2021-11-24 09:35:39.882 W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
2021-11-24 09:35:39.883 W/IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection
2021-11-24 09:35:39.884 W/IInputConnectionWrapper: getTextAfterCursor on inactive InputConnection
2021-11-24 09:35:39.888 W/IInputConnectionWrapper: getSelectedText on inactive InputConnection
2021-11-24 09:35:39.890 W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
2021-11-24 09:35:39.891 W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
2021-11-24 09:35:39.891 W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
2021-11-24 09:35:39.891 W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
2021-11-24 09:35:39.891 W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
这是我的 'composable':
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun ActivationScreen() {
var key by remember { mutableStateOf("") }
var isReady by remember {
mutableStateOf(false)
}
Column(modifier = Modifier
.padding(40.dp)
.fillMaxSize()
) {
val keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = FocusRequester()
BasicTextField(
value = key,
onValueChange = {
//isReady = it.length>11
key = it
},
singleLine = true,
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = {
keyboardController?.hide()
}
),
modifier = Modifier
.size(140.dp, 20.dp)
.background(Color.White)
.align(Alignment.CenterHorizontally)
//.focusRequester(focusRequester)
//.focusOrder(focusRequester)
)
Text(
text = "ACTIVATION",
)
val status = if (isReady) "READY" else "NOT READY"
Text(
text = status,
)
}
}
你应该避免在 Wear 上输入文字,但如果你真的需要它,GBboard activity 是最好的激活方式。
@Composable
fun TextInput() {
val label = remember { mutableStateOf("Start")}
val launcher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
it.data?.let { data ->
val results: Bundle = RemoteInput.getResultsFromIntent(data)
val ipAddress: CharSequence? = results.getCharSequence("ip_address")
label.value = ipAddress as String
}
}
Column() {
Spacer(modifier = Modifier.height(20.dp))
Chip(
label = { Text(label.value) },
onClick = {}
)
Chip(
label = { Text("Search with specific IP") },
onClick = {
val intent: Intent = RemoteInputIntentHelper.createActionRemoteInputIntent();
val remoteInputs: List<RemoteInput> = listOf(
RemoteInput.Builder("ip_address")
.setLabel("Manual IP Entry")
.wearableExtender {
setEmojisAllowed(false)
setInputActionType(EditorInfo.IME_ACTION_DONE)
}.build()
)
RemoteInputIntentHelper.putRemoteInputsExtra(intent, remoteInputs)
launcher.launch(intent)
}
)
}
}
根据@Yuri Schimke 的回答,这是一个接受占位符、值和 onChange 作为属性的通用组件实现。
import android.app.RemoteInput
import android.content.Intent
import android.os.Bundle
import android.view.inputmethod.EditorInfo
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.Text
import androidx.wear.input.RemoteInputIntentHelper
import androidx.wear.input.wearableExtender
@Composable
fun TextInput(
placeholder: String,
value: String?,
onChange: (value: String) -> Unit,
) {
val launcher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
it.data?.let { data ->
val results: Bundle = RemoteInput.getResultsFromIntent(data)
val newValue: CharSequence? = results.getCharSequence(placeholder)
onChange(newValue as String)
}
}
Column() {
Chip(
label = { Text(if (value == null || value.isEmpty()) placeholder else value) },
onClick = {
val intent: Intent = RemoteInputIntentHelper.createActionRemoteInputIntent();
val remoteInputs: List<RemoteInput> = listOf(
RemoteInput.Builder(placeholder)
.setLabel(placeholder)
.wearableExtender {
setEmojisAllowed(false)
setInputActionType(EditorInfo.IME_ACTION_DONE)
}.build()
)
RemoteInputIntentHelper.putRemoteInputsExtra(intent, remoteInputs)
launcher.launch(intent)
}
)
}
}
注意:这需要androidx.wear:wear-input:1.2.0+