mattinger
05/02/2025, 7:56 PMmattinger
05/02/2025, 7:56 PMimport androidx.activity.*
import androidx.activity.compose.LocalActivity
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@Composable
@Preview
fun ImeStatusBarIssue() {
MaterialTheme {
val activity = LocalActivity.current
SideEffect {
(activity as? ComponentActivity)?.let {
it.enableEdgeToEdge(
statusBarStyle = SystemBarStyle.light(Color.Transparent.toArgb(), Color.Transparent.toArgb()),
navigationBarStyle = SystemBarStyle.light(Color.Transparent.toArgb(), Color.Transparent.toArgb())
)
}
}
Scaffold { contentPadding ->
Column(modifier = Modifier.padding(contentPadding)) {
Column(
modifier = Modifier.weight(1f, true),
verticalArrangement = spacedBy(16.dp)
) {
Image(
modifier = Modifier.fillMaxWidth().height(400.dp),
painter = ColorPainter(Color.Blue),
contentDescription = null
)
Text(text = "Title", style = MaterialTheme.typography.headlineLarge)
Text(text = "Subtitle", style = MaterialTheme.typography.bodyLarge)
var text1 by remember { mutableStateOf("") }
OutlinedTextField(
label = { Text("Text1") },
placeholder = { Text("Enter Text") },
value = text1,
onValueChange = { text1 = it }
)
var text2 by remember { mutableStateOf("") }
OutlinedTextField(
label = { Text("Text2") },
placeholder = { Text("Enter Text") },
value = text2,
onValueChange = { text2 = it }
)
}
Button(
modifier = Modifier.fillMaxWidth(.5f).align(Alignment.CenterHorizontally),
onClick = { }
) {
Text("Click Me")
}
}
}
}
}
Alex Vanyo
05/02/2025, 8:50 PMadjustPan
behavior - what does adjustResize
give you?Mohit
05/03/2025, 5:27 AMmattinger
05/05/2025, 1:15 PMmattinger
05/05/2025, 1:42 PMMohit
05/05/2025, 1:45 PMAlex Vanyo
05/05/2025, 6:31 PM(which is deprecated by the way)You should be able to use
adjustNothing
on API 30+, and adjustResize
on API 29 and below, with the combination of handling insets directly.
Scaffold
does handle most types of insets directly by default, but it explicitly doesn’t handle ime insets by default - the reason for this is that it ends up being weird of bottom bars end up being adjust for insets.
Adding `adjustResize`/`adjustNothing` and adding imePadding()
or including WindowInsets.ime
in the insets that Scaffold
does take into account should do the trickAlex Vanyo
05/05/2025, 6:39 PMI’m wondering if i can monitor that, and detect when the image overlaps the status bar and then set the status bar to dark instead of light. Otherwise, i’m not really sure how to fix this.
adjustPan
is really hard for apps to handle directly - the best way to do the above is to switch to adjustResize
and get that information with the inset APIsmattinger
05/08/2025, 5:32 PMimePadding()
works to some degree, but the issue is that imePadding applies some padding at the bottom as well for the keyboard. We have bottom anchored Buttons in our layout, it's trying to keep that button on screen. I've tried just applying the top of the ime insets but it doesn't do anything:
val topImeInsetDp = with (LocalDensity.current) {
WindowInsets.ime.getTop(this).toDp()
}
modifier = Modifier.windowInsetsPadding(insets = WindowInsets(top = topImeInsetDp)),
I've also tried different soft input modes with no successMohit
05/09/2025, 4:41 AM@Composable
@Preview
fun ImeStatusBarIssue() {
MaterialTheme {
val activity = LocalActivity.current
SideEffect {
(activity as? ComponentActivity)?.let {
it.enableEdgeToEdge(
statusBarStyle = SystemBarStyle.light(Color.Transparent.toArgb(), Color.Transparent.toArgb()),
navigationBarStyle = SystemBarStyle.light(Color.Transparent.toArgb(), Color.Transparent.toArgb())
)
}
}
Scaffold { contentPadding ->
Column(modifier = Modifier.padding(contentPadding).imePadding()) {
Column(
modifier = Modifier.weight(1f, true).verticalScroll(
rememberScrollState()
),
verticalArrangement = spacedBy(16.dp)
) {
Image(
modifier = Modifier.fillMaxWidth().height(400.dp),
painter = ColorPainter(Color.Blue),
contentDescription = null
)
Text(text = "Title", style = MaterialTheme.typography.headlineLarge)
Text(text = "Subtitle", style = MaterialTheme.typography.bodyLarge)
var text1 by remember { mutableStateOf("") }
OutlinedTextField(
label = { Text("Text1") },
placeholder = { Text("Enter Text") },
value = text1,
onValueChange = { text1 = it },
)
var text2 by remember { mutableStateOf("") }
OutlinedTextField(
label = { Text("Text2") },
placeholder = { Text("Enter Text") },
value = text2,
onValueChange = { text2 = it }
)
}
Spacer(Modifier.height(20.dp))
Button(
modifier = Modifier.fillMaxWidth(.5f).align(Alignment.CenterHorizontally),
onClick = { }
) {
Text("Click Me")
}
}
}
}
}
mattinger
05/09/2025, 3:21 PMAlex Vanyo
05/09/2025, 8:36 PMadjustResize
/ adjustNothing
):
Scaffold { contentPadding ->
Box(modifier = Modifier.padding(contentPadding).consumeWindowInsets(contentPadding)) {
var bottomHeight by remember { mutableIntStateOf(0) }
Column(
Modifier
.align(Alignment.BottomCenter)
.zIndex(1f)
.layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
bottomHeight = placeable.height
layout(placeable.width, placeable.height) {
placeable.placeRelative(0, 0)
}
}
) {
Spacer(Modifier.height(20.dp))
Button(
modifier = Modifier.fillMaxWidth(.5f).align(Alignment.CenterHorizontally),
onClick = { }
) {
Text("Click Me")
}
}
val density = LocalDensity.current
val bottomPaddingValues = remember(density) {
object : PaddingValues {
override fun calculateBottomPadding(): Dp =
with(density) { bottomHeight.toDp() }
override fun calculateLeftPadding(layoutDirection: LayoutDirection): Dp = 0.dp
override fun calculateRightPadding(layoutDirection: LayoutDirection): Dp = 0.dp
override fun calculateTopPadding(): Dp = 0.dp
}
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(bottomPaddingValues)
.consumeWindowInsets(bottomPaddingValues)
.imePadding()
.verticalScroll(
rememberScrollState()
),
verticalArrangement = spacedBy(16.dp)
) {
Image(
modifier = Modifier.fillMaxWidth().height(400.dp),
painter = ColorPainter(Color.Blue),
contentDescription = null
)
Text(text = "Title", style = MaterialTheme.typography.headlineLarge)
Text(text = "Subtitle", style = MaterialTheme.typography.bodyLarge)
var text1 by remember { mutableStateOf("") }
OutlinedTextField(
label = { Text("Text1") },
placeholder = { Text("Enter Text") },
value = text1,
onValueChange = { text1 = it },
)
var text2 by remember { mutableStateOf("") }
OutlinedTextField(
label = { Text("Text2") },
placeholder = { Text("Enter Text") },
value = text2,
onValueChange = { text2 = it }
)
}
}
}
The logic goes something like:
You want to apply padding to the entire scrollable content, such that it aligns with the top of the bottom section, or the top of the ime insets, whichever is greater.
You can do this by measuring the size of the bottom section first, and then applying that as padding to the body section - and consuming that padding from the amount of window insets to apply. Then applying imePadding()
will pad the body content the remaining amount (if needed)Mohit
05/11/2025, 5:33 AM@Composable
@Preview
fun ImeStatusBarIssue() {
MaterialTheme {
val activity = LocalActivity.current
SideEffect {
(activity as? ComponentActivity)?.let {
it.enableEdgeToEdge(
statusBarStyle = SystemBarStyle.light(Color.Transparent.toArgb(), Color.Transparent.toArgb()),
navigationBarStyle = SystemBarStyle.light(Color.Transparent.toArgb(), Color.Transparent.toArgb())
)
}
}
val focusRequester = remember { FocusRequester() }
Scaffold { contentPadding ->
Column(modifier = Modifier.padding(contentPadding)) {
Column(
modifier = Modifier.weight(1f, true)
.verticalScroll(rememberScrollState()),
verticalArrangement = spacedBy(16.dp)
) {
Image(
modifier = Modifier.fillMaxWidth().height(400.dp),
painter = ColorPainter(Color.Blue),
contentDescription = null
)
Text(text = "Title", style = MaterialTheme.typography.headlineLarge)
Text(text = "Subtitle", style = MaterialTheme.typography.bodyLarge)
var text1 by remember { mutableStateOf("") }
OutlinedTextField(
label = { Text("Text1") },
placeholder = { Text("Enter Text") },
value = text1,
onValueChange = { text1 = it }
)
var text2 by remember { mutableStateOf("") }
OutlinedTextField(
label = { Text("Text2") },
placeholder = { Text("Enter Text") },
value = text2,
onValueChange = { text2 = it }
)
Spacer(Modifier.height(20.dp))
}
Button(
modifier = Modifier.fillMaxWidth(.5f).align(Alignment.CenterHorizontally),
onClick = { }
) {
Text("Click Me")
}
}
}
}
}