Reputation: 874
Usually when using Accompanist Modifier.statusBarsHeight()
the height will change depends on the status bar visibility, if it's visible either 24.dp or more and if it's invisible the height will be 0.dp. But i want the height won't change to zero regardless of its visibility.
I've been using this for a while:
// TODO: use better solution to get a fixed status bar height
val statusBarHeight = with (LocalDensity.current) { LocalWindowInsets.current.statusBars.top.toDp() }
val fixedStatusBarHeight = remember { statusBarHeight }
Upvotes: 19
Views: 32886
Reputation: 336
To get the statusbarheight or inset for compose you need to do the following.
Step 1: include the following in the oncreate of you activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
}
Step 2: After you included the setDecorFitsSystemWindows into your activity onCreate you need to add the following to the manifest of your activity.
android:windowSoftInputMode="adjustResize"
Step 3: To add the statusbar padding to your composable you can use the following modifier:
modifier = modifier.windowInsetsPadding(WindowInsets.safeDrawing)
Or if you want to use any other insetPaddings you can use the WindowInsets class. I've read a lot a issues on stackoverflow of people getting 0.0dp returned as there padding inset. That's because you forgot the setup part in step 1 and 2.
Hope this helps :)
Upvotes: 0
Reputation: 135
Here's how I set it, I get the height of the status bar from Resources
fun getStatusBarHeight(): Int {
val resources = Resources.getSystem()
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
return resources.getDimensionPixelSize(resourceId)
}
@Composable
fun Modifier.paddingBarHeight() = composed {
padding(top = remember { getStatusBarHeight() })
}
Upvotes: 1
Reputation: 12293
You can use WindowInsets.statusBars.getTop(this)
For example (map takes all screen - behind status and navigation bar):
GoogleMap(
modifier = Modifier.fillMaxSize(),
cameraPositionState = cameraPositionState,
properties = MapProperties(isMyLocationEnabled = true),
contentPadding = with(LocalDensity.current) {
PaddingValues(
top = WindowInsets.statusBars.getTop(this).toDp(),
bottom = WindowInsets.navigationBars.getBottom(this).toDp()
)
}
) {
Result:
Upvotes: 8
Reputation: 886
For TopAppBar
, the following code works for getting its height:
import androidx.compose.runtime.*
...
...
@Composable
fun TopAppBarComposable(){
var topAppBarHeight by remember {mutableStateOf(0.dp)}
val localDensity = LocalDensity.current
TopAppBar(
modifier = Modifier
.onGloballyPositioned { layoutCoordinates ->
with(localDensity){
topAppBarHeight = layoutCoordinates.size.height.toDp()
}
}
)
Upvotes: 1
Reputation: 923
The problem is getting complicated you should use it like this
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Box(
modifier = Modifier
.fillMaxSize()
.statusBarsPadding().navigationBarsPadding()
) {
}
Box(
modifier = Modifier
.fillMaxSize()
.statusBarsPadding().systemBarsPadding()
) {
}
}
}
}
Upvotes: 47
Reputation: 96
Currently, there is an ExperimentalLayoutApi that provides statusBarsIgnoringVisibility
.
Example use case:
I have two screens, A and B. Screen A uses statusBarsIgnoringVisibility
for top padding. In screen B, you can hide the status bar (e.g., full screen photo). When going from screen B to screen A, I want the top padding in screen A to already equal the full height of the status bar while the status bar comes back into view. Without statusBarsIgnoringVisibility
, this transition doesn't look very good.
Upvotes: 7
Reputation: 874
So i ended up making a workaround alongside with a modifier extension for easier use.
First, make a data class to hold the fixed inset values.
data class FixedInsets(
val statusBarHeight: Dp = 0.dp,
val navigationBarsPadding: PaddingValues = PaddingValues(),
)
Second, create the extension and a composition local provider.
val LocalFixedInsets = compositionLocalOf<FixedInsets> { error("no FixedInsets provided!") }
@Composable
fun Modifier.fixedStatusBarsPadding(): Modifier {
return this.padding(top = LocalFixedInsets.current.statusBarHeight)
}
@Composable
fun Modifier.fixedNavigationBarsPadding(): Modifier {
return this.padding(paddingValues = LocalFixedInsets.current.navigationBarsPadding)
}
Finally, provide the fixed inset values at the very root of your composable function.
val systemBarsPadding = WindowInsets.systemBars.asPaddingValues()
val fixedInsets = remember {
FixedInsets(
statusBarHeight = systemBarsPadding.calculateTopPadding(),
navigationBarsPadding = PaddingValues(
bottom = systemBarsPadding.calculateBottomPadding(),
start = systemBarsPadding.calculateStartPadding(LayoutDirection.Ltr),
end = systemBarsPadding.calculateEndPadding(LayoutDirection.Ltr),
),
)
}
CompositionLocalProvider(
values = arrayOf(
LocalFixedInsets provides fixedInsets,
),
) {
MainScreen()
}
Navigation bar padding example:
Text(
text = "Hello i'm a text with navigation bar padding",
modifier = Modifier
.fillMaxSize()
.background(color = Color.Red)
.fixedNavigationBarsPadding(),
)
Or you can access the sizes in Dp
directly from the local composition by using calculateXPadding()
:
val fixedInsets = LocalFixedInsets.current
Text(
text = "The navigation bar's height is: ${fixedInsets.navigationBarsPadding.calculateBottomPadding()}",
)
Upvotes: 4