如何在屏幕旋转或系统主题更改后将光标移动到 TextField 的末尾并保持键盘显示?

Pop*_*tar 5 keyboard android focus android-jetpack-compose material3

我有一个带有Textfield搜索栏的屏幕,当屏幕首次显示时,它会自动对焦。问题是,在screen rotationor system theme change(深色模式/浅色模式)之后,cursor即使 TextField 的值不为空并且键盘自行消失,也会在 TextField 的开头移动。请帮忙,我已经找了两天了。一些代码示例:

撰写版本:1.3.0 材料 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")
                    }
                },
            )
Run Code Online (Sandbox Code Playgroud)

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))
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

z.g*_*g.y 1

对于选择,问题就在这里,

value = searchInputValue.text
Run Code Online (Sandbox Code Playgroud)

您使用操作文本TextFieldValue,但您只是TextField使用普通String(TextFieldValue 的文本属性)更新值参数,您对TextFieldValue实例所做的任何操作都不会反映到您的TextField.

我使用State<TextFieldValue>'s委托对您的代码进行了一些修改

val searchInputValue by viewModel.searchInputValue
Run Code Online (Sandbox Code Playgroud)

并将其用作实际值而不是它的text属性,TextField就像这样。

value = searchInputValue
Run Code Online (Sandbox Code Playgroud)

但是你必须修改它的更新方式,所以我onValueChange也修改了,我只是.text因为我不想进一步修改其他部分而将其留给你来更改它。

 onValueChange = {
    viewModel.onEvent(SearchBookEvent.EnteredSearchValue(it.text))
 }
Run Code Online (Sandbox Code Playgroud)

你的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
      }
Run Code Online (Sandbox Code Playgroud)

应用所有这些更改,当您切换主题模式时,光标/选择将停留在末尾。

现在对于键盘问题,最初显示它,我必须实现这篇文章中的一些内容,在请求焦点之前添加延迟,

LaunchedEffect(Unit) {
    delay(200)
    focusRequester.requestFocus()
}
Run Code Online (Sandbox Code Playgroud)

为了在更改主题模式时保留键盘,我必须在活动中指定这一点。

window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED)
Run Code Online (Sandbox Code Playgroud)