I have a screen with a Textfield
as a Search bar which is autofocused when the screen is first displayed. The problem is, after screen rotation
or system theme change
(Dark mode/light mode), the cursor
moves at the beginning of TextField even if the value of TextField is not empty and the keyboard dismisses itself. Please help, I've been searching for two days. Some code samples:
Compose version: 1.3.0 Material 3: 1.0.0
SearchBookScreen.kt
val myViewModel = SearchBookViewModel()
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SearchBookScreen(
modifier: Modifier = Modifier,
navController: NavController,
viewModel: SearchBookViewModel = myViewModel,
filters: Map<SearchFilterType, FilterOptions> = FILTERS
) {
val focusRequester = remember { FocusRequester() }
val searchInputValue = viewModel.searchInputValue.value
val filtersState = viewModel.filtersState
LaunchedEffect(Unit) { this.coroutineContext.job.invokeOnCompletion { focusRequester.requestFocus() } }
Scaffold(
topBar = {
Column {
TextField(
singleLine = true,
placeholder = {
Text(text = stringResource(id = R.string.search_bar))
},
value = searchInputValue.text,
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester)
,
onValueChange = {
viewModel.onEvent(SearchBookEvent.EnteredSearchValue(it))
},
leadingIcon = {
IconButton(onClick = {
viewModel.onEvent(SearchBookEvent.ClearSearchInput)
navController.navigateUp()
}
) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = "Go back"
)
}
},
colors = TextFieldDefaults.textFieldColors(
unfocusedIndicatorColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent
),
trailingIcon = {
IconButton(onClick = { viewModel.onEvent(SearchBookEvent.ClearSearchInput) }) {
Icon(imageVector = Icons.Default.Clear, contentDescription = "clear")
}
},
)
SearchBookViewModel.kt
class SearchBookViewModel: ViewModel() {
private val _searchInputValue = mutableStateOf(TextFieldValue("", selection = TextRange.Zero))
val searchInputValue: State<TextFieldValue> = _searchInputValue
fun onEvent(event: SearchBookEvent) {
when (event) {
is SearchBookEvent.EnteredSearchValue -> {
_searchInputValue.value = searchInputValue.value.copy(text = event.value, selection = TextRange(event.value.length))
}
}
}
CodePudding user response:
For the selection, the issue is here,
value = searchInputValue.text
your'e manipulating text using TextFieldValue
but you are just updating the TextField
value parameter using ordinary String
(TextFieldValue's text property), anything you do with the TextFieldValue
instance is not reflecting to your TextField
.
I made some modifications in your code by using the State<TextFieldValue>'s
delegate
val searchInputValue by viewModel.searchInputValue
and used it as the actual value instead of its text
property to your TextField
like this.
value = searchInputValue
However you have to modify how it is being updated, so I modify onValueChange
as well, I only used .text
as I don't want to modify other parts further and to leave it for you to change it.
onValueChange = {
viewModel.onEvent(SearchBookEvent.EnteredSearchValue(it.text))
}
Your TextField
implementation should look like this
TextField(
singleLine = true,
placeholder = {
Text(text = "Type Here")
},
value = searchInputValue, // <- notice this
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester),
onValueChange = {
viewModel.onEvent(SearchBookEvent.EnteredSearchValue(it.text)) // <- and this
}
Apply all these changes and when you switch theme mode, the cursor/selection will stay at the end.
Now for the keyboard issue, showing it initially, I had to implement something from this post adding a delay prior to requesting focus,
LaunchedEffect(Unit) {
delay(200)
focusRequester.requestFocus()
}
and to retain the keyboard while changing theme mode, I had to specify this in my activity.
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED)