Scaffold implements the basic Material Design visual layout structure.
ScaffoldWithBottomBarAndCutout
@Composable
fun ScaffoldWithBottomBarAndCutout() {
val scaffoldState = rememberScaffoldState()
// Consider negative values to mean 'cut corner' and positive values to mean 'round corner'
val sharpEdgePercent = -50f
val roundEdgePercent = 45f
// Start with sharp edges
val animatedProgress = remember { Animatable(sharpEdgePercent) }
// Create a coroutineScope for the animation
val coroutineScope = rememberCoroutineScope()
// animation value to animate shape
val progress = animatedProgress.value.roundToInt()
// When progress is 0, there is no modification to the edges so we are just drawing a rectangle.
// This allows for a smooth transition between cut corners and round corners.
val fabShape =
if (progress < 0) {
CutCornerShape(abs(progress))
} else if (progress == roundEdgePercent.toInt()) {
CircleShape
} else {
RoundedCornerShape(progress)
}
// lambda to call to trigger shape animation
val changeShape: () -> Unit = {
val target = animatedProgress.targetValue
val nextTarget = if (target == roundEdgePercent) sharpEdgePercent else roundEdgePercent
coroutineScope.launch {
animatedProgress.animateTo(
targetValue = nextTarget,
animationSpec = TweenSpec(durationMillis = 600),
)
}
}
Scaffold(
scaffoldState = scaffoldState,
drawerContent = { Text("Drawer content") },
topBar = { TopAppBar(title = { Text("Scaffold with bottom cutout") }) },
bottomBar = {
BottomAppBar(cutoutShape = fabShape) {
IconButton(
onClick = { coroutineScope.launch { scaffoldState.drawerState.open() } }
) {
Icon(Icons.Filled.Menu, contentDescription = "Localized description")
}
}
},
floatingActionButton = {
ExtendedFloatingActionButton(
text = { Text("Change shape") },
onClick = changeShape,
shape = fabShape,
)
},
contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
floatingActionButtonPosition = FabPosition.Center,
isFloatingActionButtonDocked = true,
content = { innerPadding ->
LazyColumn(contentPadding = innerPadding) {
items(count = 100) {
Box(Modifier.fillMaxWidth().height(50.dp).background(colors[it % colors.size]))
}
}
},
)
}
ScaffoldWithSimpleSnackbar
@Composable
fun ScaffoldWithSimpleSnackbar() {
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
floatingActionButton = {
var clickCount by remember { mutableStateOf(0) }
ExtendedFloatingActionButton(
text = { Text("Show snackbar") },
onClick = {
// show snackbar as a suspend function
scope.launch {
scaffoldState.snackbarHostState.showSnackbar("Snackbar # ${++clickCount}")
}
},
)
},
contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
content = { innerPadding ->
Text(
text = "Body content",
modifier = Modifier.padding(innerPadding).fillMaxSize().wrapContentSize(),
)
},
)
}
SimpleScaffoldWithTopBar
@Composable
fun SimpleScaffoldWithTopBar() {
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
drawerContent = { Text("Drawer content") },
topBar = {
TopAppBar(
title = { Text("Simple Scaffold Screen") },
navigationIcon = {
IconButton(onClick = { scope.launch { scaffoldState.drawerState.open() } }) {
Icon(Icons.Filled.Menu, contentDescription = "Localized description")
}
},
)
},
floatingActionButtonPosition = FabPosition.End,
floatingActionButton = {
ExtendedFloatingActionButton(
text = { Text("Inc") },
onClick = { /* fab click handler */ },
)
},
contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
content = { innerPadding ->
LazyColumn(contentPadding = innerPadding) {
items(count = 100) {
Box(Modifier.fillMaxWidth().height(50.dp).background(colors[it % colors.size]))
}
}
},
)
}