FlexibleBottomAppBar
Composable Component
A flexible bottom app bar displays navigation and key actions at the bottom of small screens.
Common
@ExperimentalMaterial3ExpressiveApi
@Composable
fun FlexibleBottomAppBar(
modifier: Modifier = Modifier,
containerColor: Color = BottomAppBarDefaults.containerColor,
contentColor: Color = contentColorFor(containerColor),
contentPadding: PaddingValues = BottomAppBarDefaults.FlexibleContentPadding,
horizontalArrangement: Arrangement.Horizontal =
BottomAppBarDefaults.FlexibleHorizontalArrangement,
expandedHeight: Dp = BottomAppBarDefaults.FlexibleBottomAppBarHeight,
windowInsets: WindowInsets = BottomAppBarDefaults.windowInsets,
scrollBehavior: BottomAppBarScrollBehavior? = null,
content: @Composable RowScope.() -> Unit,
)
Parameters
modifier | the Modifier to be applied to this BottomAppBar |
containerColor | the color used for the background of this BottomAppBar. Use Color.Transparent to have no color. |
contentColor | the preferred color for content inside this BottomAppBar. Defaults to either the matching content color for containerColor , or to the current LocalContentColor if containerColor is not a color from the theme. |
contentPadding | the padding applied to the content of this BottomAppBar |
horizontalArrangement | the horizontal arrangement of the content inside this BottomAppBar |
expandedHeight | the maximum height this bottom bar can reach when fully expanded. If a scrollBehavior is provided, the bar might collapse or expand based on scrolling. In that case, this value sets the upper limit for the bar's height during expansion. This Dp value must be specified, finite, and greater than zero; otherwise, BottomAppBarDefaults.FlexibleBottomAppBarHeight will be used as a default. In case the scrollBehavior is null , this value will simply be the fixed height of the bottom bar. |
windowInsets | a window insets that app bar will respect. |
scrollBehavior | a BottomAppBarScrollBehavior which holds various offset values that will be applied by this bottom app bar to set up its height. A scroll behavior is designed to work in conjunction with a scrolled content to change the bottom app bar appearance as the content scrolls. Note that the bottom app bar will not react to scrolling in case a touch exploration service (e.g., TalkBack) is active. See BottomAppBarScrollBehavior.nestedScrollConnection . |
content | the content of this BottomAppBar. The default layout here is a Row , so content inside will be placed horizontally. |
Code Examples
BottomAppBarWithOverflow
/** A sample for a [FlexibleBottomAppBar] with an overflow behavior when the content doesn't fit. */
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun BottomAppBarWithOverflow() {
FlexibleBottomAppBar(
contentPadding = PaddingValues(horizontal = 96.dp),
horizontalArrangement = BottomAppBarDefaults.FlexibleFixedHorizontalArrangement,
) {
AppBarRow(
overflowIndicator = { menuState ->
IconButton(
onClick = {
if (menuState.isExpanded) {
menuState.dismiss()
} else {
menuState.show()
}
}
) {
Icon(
imageVector = Icons.Filled.MoreVert,
contentDescription = "Localized description",
)
}
}
) {
clickableItem(
onClick = { /* doSomething() */ },
icon = {
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Localized description",
)
},
label = "ArrowBack",
)
clickableItem(
onClick = { /* doSomething() */ },
icon = {
Icon(
Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = "Localized description",
)
},
label = "ArrowForward",
)
clickableItem(
onClick = { /* doSomething() */ },
icon = { Icon(Icons.Filled.Add, contentDescription = "Localized description") },
label = "Add",
)
clickableItem(
onClick = { /* doSomething() */ },
icon = { Icon(Icons.Filled.Check, contentDescription = "Localized description") },
label = "Check",
)
clickableItem(
onClick = { /* doSomething() */ },
icon = { Icon(Icons.Filled.Edit, contentDescription = "Localized description") },
label = "Edit",
)
clickableItem(
onClick = { /* doSomething() */ },
icon = {
Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
},
label = "Favorite",
)
}
}
}
ExitAlwaysBottomAppBarSpacedAround
/**
* A sample for a [FlexibleBottomAppBar] that collapses when the content is scrolled up, and appears
* when the content scrolled down. The content is spaced around.
*/
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun ExitAlwaysBottomAppBarSpacedAround() {
val scrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
bottomBar = {
FlexibleBottomAppBar(
horizontalArrangement = Arrangement.SpaceAround,
contentPadding = PaddingValues(horizontal = 0.dp),
scrollBehavior = scrollBehavior,
content = {
IconButton(onClick = { /* doSomething() */ }) {
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Localized description",
)
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(
Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = "Localized description",
)
}
FilledIconButton(
modifier = Modifier.width(56.dp),
onClick = { /* doSomething() */ },
) {
Icon(Icons.Filled.Add, contentDescription = "Localized description")
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Check, contentDescription = "Localized description")
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Edit, contentDescription = "Localized description")
}
},
)
},
content = { innerPadding ->
LazyColumn(
contentPadding = innerPadding,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
val list = (0..75).map { it.toString() }
items(count = list.size) {
Text(
text = list[it],
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
)
}
}
},
)
}
ExitAlwaysBottomAppBarSpacedBetween
/**
* A sample for a [FlexibleBottomAppBar] that collapses when the content is scrolled up, and appears
* when the content scrolled down. The content is spaced between.
*/
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun ExitAlwaysBottomAppBarSpacedBetween() {
val scrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
bottomBar = {
FlexibleBottomAppBar(
horizontalArrangement = Arrangement.SpaceBetween,
scrollBehavior = scrollBehavior,
content = {
IconButton(onClick = { /* doSomething() */ }) {
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Localized description",
)
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(
Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = "Localized description",
)
}
FilledIconButton(
modifier = Modifier.width(56.dp),
onClick = { /* doSomething() */ },
) {
Icon(Icons.Filled.Add, contentDescription = "Localized description")
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Check, contentDescription = "Localized description")
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Edit, contentDescription = "Localized description")
}
},
)
},
content = { innerPadding ->
LazyColumn(
contentPadding = innerPadding,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
val list = (0..75).map { it.toString() }
items(count = list.size) {
Text(
text = list[it],
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
)
}
}
},
)
}
ExitAlwaysBottomAppBarSpacedEvenly
/**
* A sample for a [FlexibleBottomAppBar] that collapses when the content is scrolled up, and appears
* when the content scrolled down. The content is spaced evenly.
*/
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun ExitAlwaysBottomAppBarSpacedEvenly() {
val scrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
bottomBar = {
FlexibleBottomAppBar(
horizontalArrangement = Arrangement.SpaceEvenly,
contentPadding = PaddingValues(horizontal = 0.dp),
scrollBehavior = scrollBehavior,
content = {
IconButton(onClick = { /* doSomething() */ }) {
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Localized description",
)
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(
Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = "Localized description",
)
}
FilledIconButton(
modifier = Modifier.width(56.dp),
onClick = { /* doSomething() */ },
) {
Icon(Icons.Filled.Add, contentDescription = "Localized description")
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Check, contentDescription = "Localized description")
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Edit, contentDescription = "Localized description")
}
},
)
},
content = { innerPadding ->
LazyColumn(
contentPadding = innerPadding,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
val list = (0..75).map { it.toString() }
items(count = list.size) {
Text(
text = list[it],
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
)
}
}
},
)
}
ExitAlwaysBottomAppBarFixed
/**
* A sample for a [FlexibleBottomAppBar] that collapses when the content is scrolled up, and appears
* when the content scrolled down. The content arrangement is fixed.
*/
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun ExitAlwaysBottomAppBarFixed() {
val scrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
bottomBar = {
FlexibleBottomAppBar(
horizontalArrangement = BottomAppBarDefaults.FlexibleFixedHorizontalArrangement,
scrollBehavior = scrollBehavior,
content = {
IconButton(onClick = { /* doSomething() */ }) {
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Localized description",
)
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(
Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = "Localized description",
)
}
FilledIconButton(
modifier = Modifier.width(56.dp),
onClick = { /* doSomething() */ },
) {
Icon(Icons.Filled.Add, contentDescription = "Localized description")
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Check, contentDescription = "Localized description")
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Edit, contentDescription = "Localized description")
}
},
)
},
content = { innerPadding ->
LazyColumn(
contentPadding = innerPadding,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
val list = (0..75).map { it.toString() }
items(count = list.size) {
Text(
text = list[it],
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
)
}
}
},
)
}
ExitAlwaysBottomAppBarFixedVibrant
/**
* A sample for a vibrant [FlexibleBottomAppBar] that collapses when the content is scrolled up, and
* appears when the content scrolled down. The content arrangement is fixed.
*/
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun ExitAlwaysBottomAppBarFixedVibrant() {
val scrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
bottomBar = {
FlexibleBottomAppBar(
horizontalArrangement = BottomAppBarDefaults.FlexibleFixedHorizontalArrangement,
scrollBehavior = scrollBehavior,
containerColor =
MaterialTheme.colorScheme.primaryContainer, // TODO(b/356885344): tokens
content = {
IconButton(onClick = { /* doSomething() */ }) {
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Localized description",
)
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(
Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = "Localized description",
)
}
FilledIconButton(
modifier = Modifier.width(56.dp),
onClick = { /* doSomething() */ },
) {
Icon(Icons.Filled.Add, contentDescription = "Localized description")
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Check, contentDescription = "Localized description")
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Edit, contentDescription = "Localized description")
}
},
)
},
content = { innerPadding ->
LazyColumn(
contentPadding = innerPadding,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
val list = (0..75).map { it.toString() }
items(count = list.size) {
Text(
text = list[it],
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
)
}
}
},
)
}