Compose: How to have ime padding and Scaffold padding with edge-to-edge and windowSoftInputMode is adjustResize
Asked Answered
W

4

23

The androidx.compose.material3.Scaffold padding wrongly adds the Navigation Bar padding even when soft keyboard is open the IME padding is added, resulting in a double amount of Navigation Bar padding (see screenshot below, the divider should be touching the top of the soft keyboard).

I'm trying to have the following thing to work together:

  1. App is edge-to-edge
  2. windowSoftInputMode is adjustResize
  3. having my content inside a androidx.compose.material3.Scaffold

This is the code of the MainActivity:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        WindowCompat.setDecorFitsSystemWindows(window, false)
        setContent {
            MyComposeApplicationTheme {
                Scaffold(
                    topBar = {
                        TopAppBar(
                            title = { Text(text = stringResource(id = R.string.app_name)) }
                        )
                    },
                ) { scaffoldPadding ->
                    Box(
                        modifier = Modifier
                            .fillMaxSize()
                            .padding(scaffoldPadding),
                        contentAlignment = Alignment.BottomCenter
                    ) {
                        OutlinedTextField(
                            value = "",
                            onValueChange = {},
                            modifier = Modifier
                                .fillMaxWidth()
                                .padding(horizontal = 16.dp)
                        )
                        Divider()
                    }
                }
            }
        }
    }
}

And this is how it looks: enter image description here

But, if I open the keyboard, the screen does not resizes correctly, despite having the android:windowSoftInputMode="adjustResize" attribute inside the AndroidManifest set for the Activity: enter image description here

If I use the Modifier.imePadding(), the situation is improving but now I have, beside the padding for the IME, also the inner padding of the Scaffold that is taking into account the padding for the Navigation Bar even when the keyboard is open: enter image description here

What is the right way to keep the Scaffold bottom padding without it adding the Navigation Bar padding when the IME padding is added?

EDIT
I suspect this is a bug of the Scaffold so I've created an issue on the tracker: https://issuetracker.google.com/issues/249727298

Wey answered 29/9, 2022 at 11:26 Comment(2)
Maybe you can add a copy of the answer you found in the issuetracker - I am sure others will have the same issue and end up here :)Apples
@Apples hey sure, I'll do it immediately.Wey
W
19

Currently there is no clean solution but the following workaround seems to work fine: passing WindowInsets(0, 0, 0, 0) to Scaffold and then applying .padding(scaffoldPadding).consumedWindowInsets(scaffoldPadding).systemBarsPadding() internally, or applying imePadding() internally as well.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        WindowCompat.setDecorFitsSystemWindows(window, false)
        setContent {
            MyComposeApplicationTheme {
                Scaffold(
                    modifier = Modifier.imePadding(),
                    topBar = {
                        TopAppBar(
                            title = { Text(text = stringResource(id = R.string.app_name)) }
                        )
                    },
                    bottomBar = {
                        BottomAppBar() {
                            IconButton(onClick = { }) {
                                Icon(Icons.Default.Build, null)
                            }
                        }
                    },
                    contentWindowInsets = WindowInsets(0, 0, 0, 0)
                ) { scaffoldPadding ->
                    Box(
                        modifier = Modifier
                            .fillMaxSize()
                            .padding(scaffoldPadding)
                            .consumedWindowInsets(scaffoldPadding)
                            .systemBarsPadding(),
                        contentAlignment = Alignment.BottomCenter
                    ) {
                        OutlinedTextField(
                            value = "",
                            onValueChange = {},
                            modifier = Modifier
                                .fillMaxWidth()
                                .padding(horizontal = 16.dp)

                        )
                        Divider()
                    }
                }
            }
        }
    }
}
Wey answered 23/11, 2022 at 10:30 Comment(2)
what of a case where i don't have a bottomBar and i don't need the unnecessary padding at the bottom...?Seeley
What I'm doing is to have multiple Scaffolds, once per NavGraph destination. This way each screen can have its own padding/fab.Wey
M
1

Whenever the keyboard opens up, for some reasons the values in scaffoldPadding are erroneous.

I have a TopBar but not a BottomBar. ScaffoldPadding value should be :

  • Top:64
  • Bottom:0
  • Start:0
  • End:0

But are (only after the keyboard was opened) :

  • Top:64
  • Bottom:48 (the bug ?)
  • Start:0
  • End:0

Personally to fix my issue of having en extra bottom padding in the Scaffold is not to apply the given scaffoldPadding.

        Scaffold(
        snackbarHost = { ...},
        topBar = { ...},
        content = { scaffoldPadding ->
            Box(
                modifier = Modifier.padding(top = scaffoldPadding.calculateTopPadding())
            ) {
               ...
            }
        }
    )
Mastaba answered 1/8, 2023 at 1:20 Comment(0)
H
1

I have been facing the same issue. A very simple workaround is to add the scaffold's content padding to the composable if the keyboard is not visible and remove it otherwise. Simply invoking:

import androidx.compose.foundation.layout.isImeVisible
...

val imeIsShown = WindowInsets.isImeVisible

val bottomPadding = if (imeIsShown) 0.dp else contentPadding.calculateBottomPadding()

Composable(modifier = Modifier
      .padding(bottom = bottomPadding))
Hilaryhilbert answered 15/6 at 19:55 Comment(0)
L
0

Adding windowInsets in TopAppBar worked for me.

TopAppBar(
    title = { Text(text = stringResource(id = R.string.app_name)) },
    windowInsets = WindowInsets(0, 0, 0, 0)
)
Leake answered 20/5 at 14:0 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Zipnick

© 2022 - 2024 — McMap. All rights reserved.