Hello!
I have an issue with TextField in Jetpack Compose, Android.
We have a sequence of screens where each screen has TextField, and I want to keep the keyboard open when the screen is changed to the next or previous one. But now when I change the screen, the keyboard is closed and opens what looks terribly bad to the user.
Video: https://youtube.com/shorts/RmSPGT2Rteo
Example
In original, I have separate ViewModels connected to these screens, a lot of other components on them and navigation library to make the navigation concise. This is a very simplified sample of the issue I suffer from:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
var screenIndex by remember { mutableStateOf(0) }
when (screenIndex) {
0 -> Screen(0) { screenIndex = 1 }
1 -> Screen(1) { screenIndex = 0 }
}
}
}
@Composable
fun Screen(
index: Int,
onButtonClick: () -> Unit,
) {
Column(
modifier = Modifier.fillMaxSize().imePadding(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
val focusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
var value by remember { mutableStateOf("$index") }
TextField(
modifier = Modifier.focusRequester(focusRequester),
value = value,
onValueChange = { value = it },
)
Button(onClick = onButtonClick) {
Text("Change screen")
}
}
}
What I've tried to do
I've read the source code of the CoreTextField and learnt the following: There are special function which disposes the TextInputSession when TextField is removed from the composition.
Source from CoreTextField.kt, line 316. Compose Foundation version is 1.3.1
// Hide the keyboard if made disabled or read-only while focused (b/237308379).
if (enabled && !readOnly) {
// TODO(b/230536793) This is a workaround since we don't get an explicit focus blur event
// when the text field is removed from the composition entirely.
DisposableEffect(state) {
onDispose {
if (state.hasFocus) {
onBlur(state)
}
}
}
}
Also, I've tried the following things:
- Add the delay before opening the keyboard
- Disable TextField before changing the screen (partially works but in my project screen navigation happens in the ViewModel level and it's impossible to synchronize that processes)
- Use InputMethodManager to open the keyboard, especially it's toggleSoftInput method but it's deprecated.
How can I keep the keyboard opened and move focus to the new TextField when the screen is changed?