I am using NavigationSuiteScaffold for navigation in my app. I want to add a FloatingActionButton to my app while still having adaptive navigation for small and large screens, but I can't figure out how to add elements that would usually be in a Scaffold to my app.
NavigationSuiteScaffold
has no parameters for floating action buttons (and bars)
Adding a Scaffold
inside of a NavigationSuiteScaffold
doesn't display properly on large screens
Example Image
Is there a way to display an FAB according to the Material Design Guidelines while using adaptive navigation?
This is not possible currently out of the box. There is a Feature Request open on the Google Issue Tracker, the design team is investigating it. You can leave a comment there and upvote the issue to draw more attention to it.
You can implement this yourself as follows (Screenshots below):
NavigationSuiteScaffoldFab.kt
@Composable
fun NavigationSuiteScaffoldFab(
navigationSuiteItems: NavigationSuiteScope.() -> Unit,
modifier: Modifier = Modifier,
layoutType: NavigationSuiteType =
NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(currentWindowAdaptiveInfo()),
navigationSuiteColors: NavigationSuiteColors = NavigationSuiteDefaults.colors(),
containerColor: Color = NavigationSuiteScaffoldDefaults.containerColor,
contentColor: Color = NavigationSuiteScaffoldDefaults.contentColor,
floatingActionButton: @Composable () -> Unit = {},
content: @Composable () -> Unit = {},
) {
Surface(modifier = modifier, color = containerColor, contentColor = contentColor) {
NavigationSuiteScaffoldLayout(
navigationSuite = {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
if (layoutType == NavigationSuiteType.NavigationRail
|| layoutType == NavigationSuiteType.NavigationDrawer) {
Box(
modifier = Modifier.padding(16.dp)
) {
floatingActionButton()
}
}
NavigationSuite(
layoutType = layoutType,
colors = navigationSuiteColors,
content = navigationSuiteItems
)
}
},
layoutType = layoutType,
content = {
Scaffold(
modifier = Modifier.consumeWindowInsets(
when (layoutType) {
NavigationSuiteType.NavigationBar ->
NavigationBarDefaults.windowInsets.only(WindowInsetsSides.Bottom)
NavigationSuiteType.NavigationRail ->
NavigationRailDefaults.windowInsets.only(WindowInsetsSides.Start)
NavigationSuiteType.NavigationDrawer ->
DrawerDefaults.windowInsets.only(WindowInsetsSides.Start)
else -> WindowInsets(0, 0, 0, 0)
}
),
floatingActionButton = {
if (layoutType == NavigationSuiteType.NavigationBar) {
floatingActionButton()
}
}
) {
Box(modifier = Modifier.padding(it)) {
content()
}
}
}
)
}
}
Usage
@Composable
fun NavigationSuiteDemo() {
var currentDestination by rememberSaveable { mutableStateOf(AppDestinations.HOME) }
NavigationSuiteScaffoldFab(
navigationSuiteItems = {
AppDestinations.entries.forEach {
item(
icon = {
Icon(
it.icon,
contentDescription = stringResource(it.contentDescription)
)
},
label = { Text(stringResource(it.label)) },
selected = it == currentDestination,
onClick = { currentDestination = it }
)
}
},
floatingActionButton = {
FloatingActionButton(
onClick = {}
) {
Icon(Icons.Filled.Edit, "")
}
}
) {
// TODO: Destination content.
}
}
enum class AppDestinations(
@StringRes val label: Int,
val icon: ImageVector,
@StringRes val contentDescription: Int
) {
HOME(R.string.home, Icons.Default.Home, R.string.home),
FAVORITES(R.string.favorites, Icons.Default.Favorite, R.string.favorites),
SHOPPING(R.string.shopping, Icons.Default.ShoppingCart, R.string.shopping),
PROFILE(R.string.profile, Icons.Default.AccountBox, R.string.profile),
}
Output: