Vadim Zhukov
Vadim Zhukov

Reputation: 347

Enormous ime padding in Jetpack Compose

I have a pinned bottom container with a textfield. And i use imePadding modifier. When keyboard appears seems like imePadding works twice. It happens only on some devices. Particular my is Samsung Galaxy A80 (Android 11)

Code example

Scaffold(
    modifier = Modifier.fillMaxSize(),
    bottomBar = {
        Box(
            Modifier
                .imePadding()
                .height(100.dp)
                .background(Color.Red),
        ) {
            BasicTextField(
                modifier = Modifier.fillMaxWidth(),
                value = "some text",
                onValueChange = {},
            )
        }
    },
) {
    Box(
        Modifier.fillMaxSize().padding(bottom = it.calculateBottomPadding()),
    ) {
        LazyColumn(
            modifier = Modifier.fillMaxSize(),
        ) {
            repeat((0..100).count()) {
                item {
                    Box(Modifier.fillMaxWidth().height(100.dp).background(Color.Blue)) {
                    }
                }
            }
        }
    }
}

enter image description here enter image description here

UPD Issue reproduce when I add:

window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)

Upvotes: 15

Views: 9159

Answers (3)

MohamedHarmoush
MohamedHarmoush

Reputation: 1352

I've implemented a custom modifier that adjusts the padding of a composable based on its position relative to the bottom of the window. This is useful for ensuring that the composable doesn't get covered by the keyboard (IME) when it appears, especially when imePadding() doesn't behave as expected on some devices.

Here’s the modifier:

fun Modifier.positionAwareImePadding() = composed {
    var consumePadding by remember { mutableIntStateOf(0) }
    this@positionAwareImePadding
        .onGloballyPositioned { coordinates ->
            val rootCoordinate = coordinates.findRootCoordinates()
            val bottom = coordinates.positionInWindow().y + coordinates.size.height

            consumePadding = (rootCoordinate.size.height - bottom).toInt()
        }
        .consumeWindowInsets(PaddingValues(bottom = consumePadding.pxToDp()))
        .imePadding()
}

How it works:

  • onGloballyPositioned: Captures the position of the composable relative to the screen.
  • Position Calculation: Calculates how much space is left between the composable's bottom and the bottom of the screen.
  • Custom Padding: Applies dynamic bottom padding using consumeWindowInsets to ensure the composable stays above the keyboard.
  • imePadding: Adds the default imePadding() on top of the custom logic as a fallback.

This modifier is particularly useful for handling IME (keyboard) positioning issues on devices where imePadding() alone may not work reliably.

For more information about handling Edge-to-edge and insets: https://www.youtube.com/watch?v=QRzepC9gHj4

Upvotes: 3

JD John
JD John

Reputation: 166

I also had this issue; more specifically, some devices would seem to ignore adjustResize, but adding imePadding alongside adjustResize would cause others to double it up.

I solved it for myself in the following way:

  1. Set the manifest option to android:windowSoftInputMode="adjustNothing"
  2. Set imePadding wherever needed.
  3. If setting imePadding on the contents of a scaffold, I also called, consumeWindowInsets(contentPadding) on the Modifier of those contents, before imePadding, otherwise the contentPadding got consumed additively in the imePadding.

Something like:

Scaffold(...){ contentPadding -> 
    Box(
        modifier = Modifier
            .padding(contentPadding)
            .consumeWindowInsets(contentPadding)
            .imePadding()
    ){...}
}

I can't guarantee that this is best practice or that it works in all cases, but it worked for me.

Upvotes: 15

Sri mani789
Sri mani789

Reputation: 207

add this line to activity in AndroidManifest.xml file android:windowSoftInputMode="adjustResize". The activity's layout will be resized to ensure that all of its visible content remains visible even when the soft keyboard is shown without using any imePadding() modifiers.

here you can see improved code.

var value by remember { mutableStateOf("") }
Scaffold(
    bottomBar = {
        Box(modifier = Modifier
            .fillMaxWidth()
            .background(MaterialTheme.colorScheme.surface)) {
            OutlinedTextField(
                modifier = Modifier.fillMaxWidth(), value = value,
                onValueChange = { value = it }
            )
        }
    },
) { paddingValues ->
    LazyColumn(
        modifier = Modifier
            .fillMaxSize()
            .padding(paddingValues),
        contentPadding = PaddingValues(12.dp, 16.dp),
        verticalArrangement = Arrangement.spacedBy(4.dp),
    ) {
        items(100) {
            Card(modifier = Modifier.fillMaxSize()) {
                Text(text = "Item $it",  modifier = Modifier.padding(8.dp))
            }
        }
    }
}

Upvotes: 0

Related Questions