Search code examples
android-jetpack-compose

Reduce IME padding for child composable in Jetpack Compose


I have a screen with a NavigationBar and a content screen with a TextField as follow:

+-------------------------------+
|                               |
|      Content Composable       |
|                               |
|    _____________________      |
|   |                     |     |
|   |     TextField       |     |
|   |_____________________|     |
|                               |
|                               |
|                               |
+----------+----------+---------+
|   Home   |  Search  | Profile |
+----------+----------+---------+


Column {
    Column(Modifier.verticalScroll().weight(1f)) {
        ...
        TextField(...)
    }
    NavigationBar { ... }
}

If I apply .imePadding() modifier to the inner Column, the bottom padding would be too large as it doesn't compensate for the NavigationBar and bottom system bar. How do I subtract the height of the navigation bar and bottom system bar from this IME padding?


Solution

  • WindowInsets subtraction can be done with .consumeWindowInsets(PaddingValues(...)).

    I wrote the following modifier that adjusts the padding depending on how far composable is from the bottom of the window:

    fun Modifier.positionAwareImePadding() = composed {
        var consumePadding by remember { mutableStateOf(0) }
        onGloballyPositioned { coordinates ->
            val rootCoordinate = coordinates.findRootCoordinates()
            val bottom = coordinates.positionInWindow().y + coordinates.size.height
    
            consumePadding = (rootCoordinate.size.height - bottom).toInt()
        }
            .consumeWindowInsets(PaddingValues(bottom = (consumePadding / LocalDensity.current.density).dp))
            .imePadding()
    }
    

    Example usage in OP's scenario:

    Column {
        Column(modifier = Modifier
            .positionAwareImePadding()
            .verticalScroll()
            .weight(1f)
        ) {
            ...
            TextField(...)
        }
        NavigationBar { ... }
    }