[Compose] 使用 Compose 在 Android 中的脚手架 Scaffold

7,427 阅读1分钟

Compose 提供了大量基于 Material Design 的可组合项以及依赖项,旨在简化界面的构建。诸如 DrawerFloatingActionButtonTopAppBar 之类的元素都有提供。Material 组件大量使用槽位 API,这是 Compose 引入的一种模式,可在组合项之上带来一层自定义设置。可组合项通常采用 lambda (content: @Composable () -> Unit)。

Scaffold 可以实现具有基本 Material Design 布局结构的界面。Scaffold 可以为最常见的顶级 Material 组件(如 TopAppBarBottomAppBarFloatingActionButtonDrawer)提供槽位。通过使用 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 (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

@Composable
fun TopBar(onMenuClicked: () -> Unit) {
    TopAppBar(
        title = {
            Text(text = "Scaffold Example", color = Color.White)
        },
        navigationIcon = {
            Icon(
                imageVector = Icons.Default.Menu,
                contentDescription = "Menu",
                modifier = Modifier.clickable(onClick = onMenuClicked),
                tint = Color.White
            )
        },
        backgroundColor = Purple700,
        elevation = 12.dp
    )
}

创建 BottomBar

@Composable
fun BottomBar() {
    BottomAppBar(
        backgroundColor = Purple700
    ) {
        Text(text = "BottomAppBar", color = Color.White)
    }
}

创建 Content

@Composable
fun Content() {
    Column(
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier
            .fillMaxSize()
            .background(Color.White)
    ) {
        Text(text = "Content", color = Purple700)
    }
}

创建 Drawer

@Composable
fun Drawer() {
    Column(
        Modifier
            .background(Color.White)
            .fillMaxSize()
    ) {
        repeat(5) { item ->
            Text(text = "Item $item", modifier = Modifier.padding(8.dp), color = Color.Black)
        }
    }
}

实现 FloatingActionButton 点击弹出 SnackBar

FloatingActionButton(
    onClick = {
        coroutineScope.launch {
            when (scaffoldState.snackbarHostState.showSnackbar(
                message = "Snack Bar",
                actionLabel = "Dismiss"
            )) {
                SnackbarResult.Dismissed -> {
                }

                SnackbarResult.ActionPerformed -> {
                }
            }
        }
    }
) {
    Text(text = "+", color = Color.White, fontSize = 26.sp)
}

所有需要的组件都创建完成,来组合 Scaffold。

@Composable
fun ScaffoldExample() {
    val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Closed))
    val coroutineScope = rememberCoroutineScope()

    Scaffold(
        scaffoldState = scaffoldState,
        topBar = {
            TopBar(
                onMenuClicked = {
                    coroutineScope.launch {
                        scaffoldState.drawerState.open()
                    }
                })
        },
        bottomBar = { BottomBar() },
        drawerContent = {
            Drawer()
        },
        content = {
            Content()
        },
        floatingActionButton = {
            FloatingActionButton(
                onClick = {
                    coroutineScope.launch {
                        when (scaffoldState.snackbarHostState.showSnackbar(
                            message = "Snack Bar",
                            actionLabel = "Dismiss"
                        )) {
                            SnackbarResult.Dismissed -> {
                            }

                            SnackbarResult.ActionPerformed -> {
                            }
                        }
                    }
                }
            ) {
                Text(text = "+", color = Color.White, fontSize = 26.sp)
            }
        }
    )
}

然后就可以在 Activity 中从 setContent 里调用 Scaffold 组合了。

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Surface(color = Color.White) {
                ScaffoldExample()
            }
        }
    }
}

Done!

image.png

Github

完整代码