Scaffold
@Composable
fun Scaffold(
modifier: Modifier? = Modifier,
scaffoldState: ScaffoldState? = rememberScaffoldState(),
topBar: (@Composable () -> Unit)? = {},
bottomBar: (@Composable () -> Unit)? = {},
snackbarHost: (@Composable (SnackbarHostState) -> Unit)? = { SnackbarHost(it) },
floatingActionButton: (@Composable () -> Unit)? = {},
floatingActionButtonPosition: FabPosition? = FabPosition.End,
isFloatingActionButtonDocked: Boolean? = false,
drawerContent: (@Composable @ExtensionFunctionType ColumnScope.() -> Unit)? = null,
drawerGesturesEnabled: Boolean? = true,
drawerShape: Shape? = MaterialTheme.shapes.large,
drawerElevation: Dp? = DrawerDefaults.Elevation,
drawerBackgroundColor: Color? = MaterialTheme.colors.surface,
drawerContentColor: Color? = contentColorFor(drawerBackgroundColor),
drawerScrimColor: Color? = DrawerDefaults.scrimColor,
backgroundColor: Color? = MaterialTheme.colors.background,
contentColor: Color? = contentColorFor(backgroundColor),
content: (@Composable (PaddingValues) -> Unit)?
): Unit
Scaffold 是系统提供的一种脚手架,可以快速的搭建一个页面结构,包含
- topBar 通常是一个 TopAppBar
- bottomBar 通常是一个 BottomNavigation
- floatingActionButton 悬浮按钮
- floatingActionButtonPosition 悬浮按钮位置
- isFloatingActionButtonDocked 悬浮按钮是否贴到 bottomBar 上
- drawerContent 侧滑菜单
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun ScaffoldSample2() {
val bottomData = listOf("Home", "List", "User")
var bottomNavigationCurrentIndex by remember {
mutableStateOf(0)
}
Scaffold(
topBar = {
TopAppBar(title = { Text(text = "Title") }, navigationIcon = {
Icon(imageVector = Icons.Default.NavigateBefore, contentDescription = null)
}, actions = {
Icon(imageVector = Icons.Default.Add, contentDescription = null)
})
},
bottomBar = {
BottomNavigation() {
bottomData.forEachIndexed { index, item ->
BottomNavigationItem(
selected = bottomNavigationCurrentIndex == index,
onClick = { bottomNavigationCurrentIndex = index }, icon = {
BadgeBox(badgeContent = {
Text("1")
}) {
Icon(
imageVector = Icons.Default.AccountBox,
contentDescription = null
)
}
}, label = { Text(item) })
}
}
},
floatingActionButton = {
ExtendedFloatingActionButton(
icon = {
Icon(
imageVector = Icons.Default.SupervisedUserCircle,
contentDescription = null
)
},
text = { Text("Button") },
onClick = { /*TODO*/ })
},
floatingActionButtonPosition = FabPosition.Center,
isFloatingActionButtonDocked = true
) {
Text("Body Content")
}
}
BackdropScaffold¶
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun ScaffoldSample6() {
val scope = rememberCoroutineScope()
val selection = remember { mutableStateOf(1) }
val scaffoldState = rememberBackdropScaffoldState(BackdropValue.Concealed)
LaunchedEffect(scaffoldState) {
scaffoldState.reveal()
}
BackdropScaffold(
scaffoldState = scaffoldState,
appBar = {
TopAppBar(
title = { Text("Backdrop scaffold") },
navigationIcon = {
if (scaffoldState.isConcealed) {
IconButton(onClick = { scope.launch { scaffoldState.reveal() } }) {
Icon(Icons.Default.Menu, contentDescription = "Localized description")
}
} else {
IconButton(onClick = { scope.launch { scaffoldState.conceal() } }) {
Icon(Icons.Default.Close, contentDescription = "Localized description")
}
}
},
actions = {
var clickCount by remember { mutableStateOf(0) }
IconButton(
onClick = {
// show snackbar as a suspend function
scope.launch {
scaffoldState.snackbarHostState
.showSnackbar("Snackbar #${++clickCount}")
}
}
) {
Icon(Icons.Default.Favorite, contentDescription = "Localized description")
}
},
elevation = 0.dp,
backgroundColor = Color.Transparent
)
},
backLayerContent = {
LazyColumn {
items(if (selection.value >= 3) 3 else 5) {
ListItem(
Modifier.clickable {
selection.value = it
scope.launch { scaffoldState.conceal() }
},
text = { Text("Select $it") }
)
}
}
},
frontLayerContent = {
Text("Selection: ${selection.value}")
LazyColumn {
items(50) {
ListItem(
text = { Text("Item $it") },
icon = {
Icon(
Icons.Default.Favorite,
contentDescription = "Localized description"
)
}
)
}
}
}
)
}
BottomSheetScaffold¶
在 Scaffold 的基础上还可以从底部上拉出菜单
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun ScaffoldSample7() {
val scope = rememberCoroutineScope()
val scaffoldState = rememberBottomSheetScaffoldState()
BottomSheetScaffold(
sheetContent = {
Box(
Modifier.fillMaxWidth().height(128.dp),
contentAlignment = Alignment.Center
) {
Text("Swipe up to expand sheet")
}
Column(
Modifier.fillMaxWidth().padding(64.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Sheet content")
Spacer(Modifier.height(20.dp))
Button(
onClick = {
scope.launch { scaffoldState.bottomSheetState.collapse() }
}
) {
Text("Click to collapse sheet")
}
}
},
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
title = { Text("Bottom sheet scaffold") },
navigationIcon = {
IconButton(onClick = { scope.launch { scaffoldState.drawerState.open() } }) {
Icon(Icons.Default.Menu, contentDescription = "Localized description")
}
}
)
},
floatingActionButton = {
var clickCount by remember { mutableStateOf(0) }
FloatingActionButton(
onClick = {
// show snackbar as a suspend function
scope.launch {
scaffoldState.snackbarHostState.showSnackbar("Snackbar #${++clickCount}")
}
}
) {
Icon(Icons.Default.Favorite, contentDescription = "Localized description")
}
},
floatingActionButtonPosition = FabPosition.End,
sheetPeekHeight = 128.dp,
drawerContent = {
Column(
Modifier.fillMaxWidth().padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Drawer content")
Spacer(Modifier.height(20.dp))
Button(onClick = { scope.launch { scaffoldState.drawerState.close() } }) {
Text("Click to close drawer")
}
}
}
) { innerPadding ->
LazyColumn(contentPadding = innerPadding) {
items(100) {
Box(
Modifier
.fillMaxWidth()
.height(50.dp)
)
}
}
}
}