ToggleFloatingActionButton
Common
Component in Material 3 Compose
Toggleable FAB supports animating its container size, corner radius, and color when it is toggled, and should be used in conjunction with a [FloatingActionButtonMenu] to provide additional choices to the user after clicking the FAB.
Use [ToggleFloatingActionButtonDefaults.animateIcon] to animate the color and size of the icon while the [ToggleFloatingActionButton] is being toggled.
Last updated:
Installation
dependencies {
implementation("androidx.compose.material3:material3:1.4.0-alpha02")
}
Overloads
@ExperimentalMaterial3ExpressiveApi
@Composable
fun ToggleFloatingActionButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
containerColor: (Float) -> Color = ToggleFloatingActionButtonDefaults.containerColor(),
contentAlignment: Alignment = Alignment.TopEnd,
containerSize: (Float) -> Dp = ToggleFloatingActionButtonDefaults.containerSize(),
containerCornerRadius: (Float) -> Dp =
ToggleFloatingActionButtonDefaults.containerCornerRadius(),
content: @Composable ToggleFloatingActionButtonScope.() -> Unit,
)
Parameters
name | description |
---|---|
checked | whether this Toggleable FAB is checked |
onCheckedChange | callback to be invoked when this Toggleable FAB is clicked, therefore the change of the state in requested |
modifier | the [Modifier] to be applied to this Toggleable FAB |
containerColor | the color used for the background of this Toggleable FAB, based on the checked progress value from 0-1 |
contentAlignment | the alignment of this Toggleable FAB when checked |
containerSize | the size of this Toggleable FAB, based on the checked progress value from 0-1 |
containerCornerRadius | the corner radius of this Toggleable FAB, based on the checked progress value from 0-1 |
content | the content of this Toggleable FAB, typically an [Icon] that switches from an Add to a Close sign at 50% checked progress |
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) },
)
}
}
}
}