android-jetpackandroid-jetpack-composeandroid-jetpack-compose-listandroid-compose-textfield

TextField is hiding under the keyboard when focused


I have a problem with TextField that is hiding under the keyboard, I've found the answers for the similar question here, but they are not helping me in my case. I have a LazyColumn with the list of different composables in it, and when I have not enough elements in the window for scroll to be activated, focusing on TextField is not lifting up focused TextField above keyboard. Keyboard just hides it. My code:

val listState = rememberLazyListState()
typealias ComposableType = @Composable (Int) -> Unit
val uiList = listOf<ComposableType>( {IconButton}, {Text}, {CustomTextField(listState,it)}, {CustomTextField(listState,it)})
LazyColumn() {
    itemsIndexed(uiList) { index, ui ->
                ui.invoke(index)
        }
}

val scope = rememberCoroutineScope()
@Composable
CustomTextField(scrollState: LazyListState, position: Int) {
    OutlinedTextField(
        modifier = Modifier.onFocusEvent { focusState ->
            if (focusState.isFocused) {
                scope.launch {
                    scrollState.animateScrollToItem(position)
                }
            }
    )    
}

So, for example if i have 10 CustomTextFields in my uiList, scroll works when one of TextField is focused. But when there are only 2 TextFields in the uiList, focusing on either of them does not lift up them above keyboard.

Also I tried using RelocationRequester() and used Column with scroll instead of LazyColumn, none of it helped.


Solution

  • It's a combination of things...

    1. You need to add this in your activity's declaration in Android.xml
    android:windowSoftInputMode="adjustResize"
    
    1. Use BringIntoViewRequester as modifier in your TextField as you mentioned.
    .bringIntoViewRequester(yourBringIntoViewRequester)
    
    1. The steps above worked for me when the component gain focus programatically (using FocusRequester). However, when the user taps on the TextField, it didn't work for me. So I implemented a workaround (which I'm not very proud of): when the TextField gain focus, I wait a bit to use the RelocationRequester. So I added this modifier to my TextField.
    .onFocusEvent {
        if (it.isFocused) {
            coroutineScope.launch {
                delay(200)
                yourBringIntoViewRequester.bringIntoView()
            }
        }
    }
    

    These three things worked for me.