FloatingActionButtonMenu
Common
Component in Material 3 Compose
FAB Menus should be used in conjunction with a [ToggleFloatingActionButton] to provide additional choices to the user after clicking a FAB.
Last updated:
Installation
dependencies {
implementation("androidx.compose.material3:material3:1.4.0-alpha02")
}
Overloads
@ExperimentalMaterial3ExpressiveApi
@Composable
fun FloatingActionButtonMenu(
expanded: Boolean,
button: @Composable () -> Unit,
modifier: Modifier = Modifier,
horizontalAlignment: Alignment.Horizontal = Alignment.End,
content: @Composable FloatingActionButtonMenuScope.() -> Unit
)
Parameters
name | description |
---|---|
expanded | whether the FAB Menu is expanded, which will trigger a staggered animation of the FAB Menu Items |
button | a composable which triggers the showing and hiding of the FAB Menu Items via the [expanded] state, typically a [ToggleFloatingActionButton] |
modifier | the [Modifier] to be applied to this FAB Menu |
horizontalAlignment | the horizontal alignment of the FAB Menu Items |
content | the content of this FAB Menu, typically a list of [FloatingActionButtonMenuItem]s |
Code Example
FloatingActionButtonMenuSample
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun FloatingActionButtonMenuSample() {
val listState = rememberLazyListState()
val fabVisible by remember { derivedStateOf { listState.firstVisibleItemIndex == 0 } }
Box {
LazyColumn(state = listState, modifier = Modifier.fillMaxSize()) {
for (index in 0 until 100) {
item { Text(text = "List item - $index", modifier = Modifier.padding(24.dp)) }
}
}
val items =
listOf(
Icons.AutoMirrored.Filled.Message to "Reply",
Icons.Filled.People to "Reply all",
Icons.Filled.Contacts to "Forward",
Icons.Filled.Snooze to "Snooze",
Icons.Filled.Archive to "Archive",
Icons.AutoMirrored.Filled.Label to "Label",
)
var fabMenuExpanded by rememberSaveable { mutableStateOf(false) }
BackHandler(fabMenuExpanded) { fabMenuExpanded = false }
FloatingActionButtonMenu(
modifier = Modifier.align(Alignment.BottomEnd),
expanded = fabMenuExpanded,
button = {
ToggleFloatingActionButton(
modifier =
Modifier.semantics {
traversalIndex = -1f
stateDescription = if (fabMenuExpanded) "Expanded" else "Collapsed"
contentDescription = "Toggle menu"
}
.animateFloatingActionButton(
visible = fabVisible || fabMenuExpanded,
alignment = Alignment.BottomEnd
),
checked = fabMenuExpanded,
onCheckedChange = { fabMenuExpanded = !fabMenuExpanded }
) {
val imageVector by remember {
derivedStateOf {
if (checkedProgress > 0.5f) Icons.Filled.Close else Icons.Filled.Add
}
}
Icon(
painter = rememberVectorPainter(imageVector),
contentDescription = null,
modifier = Modifier.animateIcon({ checkedProgress })
)
}
}
) {
items.forEachIndexed { i, item ->
FloatingActionButtonMenuItem(
modifier =
Modifier.semantics {
isTraversalGroup = true
// Add a custom a11y action to allow closing the menu when focusing
// the last menu item, since the close button comes before the first
// menu item in the traversal order.
if (i == items.size - 1) {
customActions =
listOf(
CustomAccessibilityAction(
label = "Close menu",
action = {
fabMenuExpanded = false
true
}
)
)
}
},
onClick = { fabMenuExpanded = false },
icon = { Icon(item.first, contentDescription = null) },
text = { Text(text = item.second) },
)
}
}
}
}