Как переместить курсор в конец TextField после поворота экрана или изменения системной темы и сохранить отображение клавиатуры?

У меня есть экран сTextfieldкак панель поиска, которая автоматически фокусируется при первом отображении экрана. Проблема в том, что послеscreen rotationилиsystem theme change(темный режим/светлый режим),cursorперемещается в начало TextField, даже если значение TextField не пусто и клавиатура закрывается. Помогите пожалуйста, два дня ищу. Некоторые примеры кода:

Версия компоновки: 1.3.0 Материал 3: 1.0.0

ПоискBookScreen.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))
            }
        }
    }

1 ответ

Для выбора, вопрос здесь,

      value = searchInputValue.text

вы манипулируете текстом, используя, но вы просто обновляете параметр значения, используя обычныеString(текстовое свойство TextFieldValue), все, что вы делаете сTextFieldValueэкземпляр не отражает ваш .

Я внес некоторые изменения в ваш код, используяState<TextFieldValue>'sделегировать

      val searchInputValue by viewModel.searchInputValue

и использовал его как фактическое значение вместо егоtextсвойство для вашего нравится это.

      value = searchInputValue

Однако вам нужно изменить способ его обновления, поэтому я изменяюonValueChangeтакже, я только использовал.textтак как я не хочу вносить изменения в другие части и оставлять это на ваше усмотрение.

       onValueChange = {
    viewModel.onEvent(SearchBookEvent.EnteredSearchValue(it.text))
 }

ТвойTextFieldреализация должна выглядеть так

      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
      }

Примените все эти изменения, и при переключении режима темы курсор/выделение останется в конце.

Теперь о проблеме с клавиатурой, показывающей ее изначально, мне пришлось реализовать что-то из этого поста , добавив задержку перед запросом фокуса,

      LaunchedEffect(Unit) {
    delay(200)
    focusRequester.requestFocus()
}

и чтобы сохранить клавиатуру при изменении режима темы, мне пришлось указать это в своей деятельности.

      window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED)
Другие вопросы по тегам