I'm developing an app using jetpack compose and I ran into issues while positioning my content inside of the space left in between the top bar and the bottom navigation bar, what I'm looking for is a way to send their height between screens to use as padding.
In my MainActivity I'm using a custom AppBar and the voyager navigation bar, with the Content of my screens between them.
class MainActivity : ComponentActivity() {
companion object {
var navigationHeight = mutableStateOf(0.dp)
var topAppBarHeight = mutableStateOf(0.dp)
}
override fun onCreate(savedInstanceState: Bundle?) {
R2DroidApplication.defaultEnvironment.initEnvironment()
super.onCreate(savedInstanceState)
setContent {
Rr2DroidDynamicTheme {
Content()
}
}
}
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun Content() {
TabNavigator(HomeTab) {
Scaffold(
content = {
CurrentTab()
},
topBar = {
AppBar(title = stringResource(id = R.string.app_name), canGoBack = false,
modifier = Modifier.onGloballyPositioned { layoutCoordinates ->
topAppBarHeight.value = layoutCoordinates.size.height.dp
})
},
bottomBar = {
NavigationBar(modifier = Modifier.onGloballyPositioned { layoutCoordinates ->
navigationHeight.value = layoutCoordinates.size.height.dp
}) {
TabNavigationItem(tab = HomeTab)
TabNavigationItem(tab = PackageManagerTab)
}
}
)
}
}
@Composable
private fun RowScope.TabNavigationItem(tab: Tab) {
val tabNavigator = LocalTabNavigator.current
NavigationBarItem(
selected = tabNavigator.current.key == tab.key,
alwaysShowLabel = true,
label = { Text(text = tab.options.title) },
onClick = { tabNavigator.current = tab },
icon = { Icon(painter = tab.options.icon!!, contentDescription = tab.options.title) }
)
}
}
My AppBar is a simple Box that contains a CenterAlignedTopBar and a linear progress bar to show the progress:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppBar(title: String, canGoBack: Boolean = true, contentLoaded: Boolean = false, modifier: Modifier = Modifier) {
val navigator = LocalNavigator.currentOrThrow
Box() {
Column() {
CenterAlignedTopAppBar(
colors = TopAppBarDefaults.topAppBarColors(
containerColor = LocalDynamicThemeState.current.colorTuple.value.surface!!,
titleContentColor = LocalDynamicThemeState.current.colorTuple.value.primary,
),
title = {
Text(title)
},
navigationIcon = {
if (canGoBack) {
IconButton(onClick = {navigator.pop()}) {
Icon(
painter = painterResource(id = R.drawable.back),
contentDescription = stringResource(id = R.string.back)
)
}
}
}
)
IndeterminateLinearIndicator(isLoading = contentLoaded)
Divider()
}
}
}
@Composable
fun IndeterminateLinearIndicator(isLoading: Boolean = false) {
var loading by remember { mutableStateOf(isLoading) }
if (!loading) return
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth(),
color = MaterialTheme.colorScheme.secondary,
trackColor = MaterialTheme.colorScheme.surfaceVariant,
)
}
My Screen content is rendered in a Tab
object PackageManagerTab : Tab {
val packageManagerScreen = PackageManagerScreen()
override val options: TabOptions
@Composable
get() {
val title = stringResource(R.string.package_manager)
val icon = rememberVectorPainter(image = FeatherIcons.Package)
return remember {
TabOptions(
index = 0u,
title = title,
icon = icon
)
}
}
@Composable
override fun Content() {
Box() {
packageManagerScreen.Content()
}
}
}
The screen is a simple BottomSheetScaffold with content and sheet content.
How do I proceed?
The Scaffold
Composable passes a innerPadding: PaddingValues
parameter to the content
Composable. This parameter holds the padding that should be applied to the content
in order to make sure that the content
is not overlapped by the topBar
and bottomBar
. You can wrap your CurrentTab()
in a Box Composable any apply the padding there:
Scaffold(
content = { innerPadding -> // parameter containing top and bottom padding
Box(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding) // apply padding
) {
CurrentTab()
}
},
topBar = {
//...
},
bottomBar = {
//...
}
)
Side Note:
Please also check your dependencies in your module's build.gradle
file. Because since a fairly long time, you would be getting a compiler error saying
This might indicate that you are using deprecated components.