使用 Jetpack Compose 在 Android 中搭建脚手架
有很多应用程序包含 TopAppBar、Drawer、Floating Action Button、BottomAppBar(以底部导航的形式)、Snackbar。虽然您可以在一个应用程序中单独设置所有这些,但需要进行大量设置。 Jetpack Compose 提供了Scaffold Composable ,可以节省大量时间。它就像一个预先构建的模板。在本文中,我们将看到如何使用 Jetpack Compose 在 android 中设置 Scaffold。我们将构建一个基本的应用程序来演示可组合的 Scaffold,这是一个展示该应用程序的视频。
先决条件:
- 对 Kotlin 的了解。
- Jetpack Compose 的知识。
分步实施
第 1 步:创建 TopAppBar
打开MainActivity.kt并创建一个 TopBar Composable函数,它将是我们在 Scaffold 中的 TopAppBar 的包装器。
Kotlin
// A function which will receive a
// callback to trigger to opening the drawer
@Composable
fun TopBar(onMenuClicked: () -> Unit) {
// TopAppBar Composable
TopAppBar(
// Provide Title
title = {
Text(text = "Scaffold||GFG", color = Color.White)
},
// Provide the navigation Icon (Icon on the left to toggle drawer)
navigationIcon = {
Icon(
imageVector = Icons.Default.Menu,
contentDescription = "Menu",
// When clicked trigger onClick
// Callback to trigger drawer open
modifier = Modifier.clickable(onClick = onMenuClicked),
tint = Color.White
)
},
// background color of topAppBar
backgroundColor = Color(0xFF0F9D58)
)
}
Kotlin
@Composable
fun BottomBar() {
// BottomAppBar Composable
BottomAppBar(
backgroundColor = Color(0xFF0F9D58)
) {
Text(text = "Bottom App Bar", color = Color.White)
}
}
Kotlin
@Composable
fun Drawer() {
// Column Composable
Column(
Modifier
.background(Color.White)
.fillMaxSize()
) {
// Repeat is a loop which
// takes count as argument
repeat(5) { item ->
Text(text = "Item number $item", modifier = Modifier.padding(8.dp), color = Color.Black)
}
}
}
Kotlin
@Composable
fun Body() {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
Text(text = "Body Content", color = Color(0xFF0F9D58))
}
}
Kotlin
@Composable
fun ScaffoldExample() {
// create a scaffold state, set it to close by default
val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Closed))
// Create a coroutine scope. Opening of
// Drawer and snackbar should happen in
// background thread without blocking main thread
val coroutineScope = rememberCoroutineScope()
// Scaffold Composable
Scaffold(
// pass the scaffold state
scaffoldState = scaffoldState,
// pass the topbar we created
topBar = {
TopBar(
// When menu is clicked open the
// drawer in coroutine scope
onMenuClicked = {
coroutineScope.launch {
// to close use -> scaffoldState.drawerState.close()
scaffoldState.drawerState.open()
}
})
},
// pass the bottomBar
// we created
bottomBar = { BottomBar() },
// Pass the body in
// content parameter
content = {
Body()
},
// pass the drawer
drawerContent = {
Drawer()
},
floatingActionButton = {
// Create a floating action button in
// floatingActionButton parameter of scaffold
FloatingActionButton(
onClick = {
// When clicked open Snackbar
coroutineScope.launch {
when (scaffoldState.snackbarHostState.showSnackbar(
// Message In the snackbar
message = "Snack Bar",
actionLabel = "Dismiss"
)) {
SnackbarResult.Dismissed -> {
// do something when
// snack bar is dismissed
}
SnackbarResult.ActionPerformed -> {
// when it appears
}
}
}
}) {
// Simple Text inside FAB
Text(text = "X")
}
}
)
}
Kotlin
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Surface(color = Color.White) {
// Scaffold we created
ScaffoldExample()
}
}
}
}
Kotlin
package com.gfg.scaffoldjetpackcompose
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Surface(color = Color.White) {
// Scaffold we created
ScaffoldExample()
}
}
}
}
@Composable
fun ScaffoldExample() {
// create a scaffold state, set it to close by default
val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Closed))
// Create a coroutine scope. Opening of Drawer
// and snackbar should happen in background
// thread without blocking main thread
val coroutineScope = rememberCoroutineScope()
// Scaffold Composable
Scaffold(
// pass the scaffold state
scaffoldState = scaffoldState,
// pass the topbar we created
topBar = {
TopBar(
// When menu is clicked open the
// drawer in coroutine scope
onMenuClicked = {
coroutineScope.launch {
// to close use -> scaffoldState.drawerState.close()
scaffoldState.drawerState.open()
}
})
},
// pass the bottomBar we created
bottomBar = { BottomBar() },
// Pass the body in
// content parameter
content = {
Body()
},
// pass the drawer
drawerContent = {
Drawer()
},
floatingActionButton = {
// Create a floating action button in
// floatingActionButton parameter of scaffold
FloatingActionButton(
onClick = {
// When clicked open Snackbar
coroutineScope.launch {
when (scaffoldState.snackbarHostState.showSnackbar(
// Message In the snackbar
message = "Snack Bar",
actionLabel = "Dismiss"
)) {
SnackbarResult.Dismissed -> {
// do something when
// snack bar is dismissed
}
SnackbarResult.ActionPerformed -> {
// when it appears
}
}
}
}) {
// Simple Text inside FAB
Text(text = "X")
}
}
)
}
// A function which will receive a
// callback to trigger to opening the drawer
@Composable
fun TopBar(onMenuClicked: () -> Unit) {
// TopAppBar Composable
TopAppBar(
// Provide Title
title = {
Text(text = "Scaffold||GFG", color = Color.White)
},
// Provide the navigation Icon ( Icon on the left to toggle drawer)
navigationIcon = {
Icon(
imageVector = Icons.Default.Menu,
contentDescription = "Menu",
// When clicked trigger onClick
// Callback to trigger drawer open
modifier = Modifier.clickable(onClick = onMenuClicked),
tint = Color.White
)
},
// background color of topAppBar
backgroundColor = Color(0xFF0F9D58)
)
}
@Composable
fun BottomBar() {
// BottomAppBar Composable
BottomAppBar(
backgroundColor = Color(0xFF0F9D58)
) {
Text(text = "Bottom App Bar", color = Color.White)
}
}
@Composable
fun Body() {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
Text(text = "Body Content", color = Color(0xFF0F9D58))
}
}
@Composable
fun Drawer() {
// Column Composable
Column(
Modifier
.background(Color.White)
.fillMaxSize()
) {
// Repeat is a loop which
// takes count as argument
repeat(5) { item ->
Text(text = "Item number $item", modifier = Modifier.padding(8.dp), color = Color.Black)
}
}
}
第二步:创建BottomAppBar
打开MainActivity.kt并创建一个BottomBar Composable。在我们的应用程序中,这将是一个简单的直接前进。
科特林
@Composable
fun BottomBar() {
// BottomAppBar Composable
BottomAppBar(
backgroundColor = Color(0xFF0F9D58)
) {
Text(text = "Bottom App Bar", color = Color.White)
}
}
第 3 步:创建抽屉内容
打开MainActivity.kt并创建一个可组合的 Drawer,它将成为我们 Scaffold 中的 drawer。
科特林
@Composable
fun Drawer() {
// Column Composable
Column(
Modifier
.background(Color.White)
.fillMaxSize()
) {
// Repeat is a loop which
// takes count as argument
repeat(5) { item ->
Text(text = "Item number $item", modifier = Modifier.padding(8.dp), color = Color.Black)
}
}
}
第 4 步:创建 Scaffold 的主体部分
创建另一个可组合的函数体。它将是我们应用程序中可组合的简单文本。在其他应用程序中实现它时,请务必对其进行自定义。
科特林
@Composable
fun Body() {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
Text(text = "Body Content", color = Color(0xFF0F9D58))
}
}
由于我们需要的所有组件都已完成,让我们开始处理 Scaffold Part。
第 5 步:使用 Scaffold
由于我们已经创建了所有组件,因此 Scaffold 代码将非常简单且不言自明。
科特林
@Composable
fun ScaffoldExample() {
// create a scaffold state, set it to close by default
val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Closed))
// Create a coroutine scope. Opening of
// Drawer and snackbar should happen in
// background thread without blocking main thread
val coroutineScope = rememberCoroutineScope()
// Scaffold Composable
Scaffold(
// pass the scaffold state
scaffoldState = scaffoldState,
// pass the topbar we created
topBar = {
TopBar(
// When menu is clicked open the
// drawer in coroutine scope
onMenuClicked = {
coroutineScope.launch {
// to close use -> scaffoldState.drawerState.close()
scaffoldState.drawerState.open()
}
})
},
// pass the bottomBar
// we created
bottomBar = { BottomBar() },
// Pass the body in
// content parameter
content = {
Body()
},
// pass the drawer
drawerContent = {
Drawer()
},
floatingActionButton = {
// Create a floating action button in
// floatingActionButton parameter of scaffold
FloatingActionButton(
onClick = {
// When clicked open Snackbar
coroutineScope.launch {
when (scaffoldState.snackbarHostState.showSnackbar(
// Message In the snackbar
message = "Snack Bar",
actionLabel = "Dismiss"
)) {
SnackbarResult.Dismissed -> {
// do something when
// snack bar is dismissed
}
SnackbarResult.ActionPerformed -> {
// when it appears
}
}
}
}) {
// Simple Text inside FAB
Text(text = "X")
}
}
)
}
现在从Mainactivity类中的 setContent 调用这个可组合
科特林
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Surface(color = Color.White) {
// Scaffold we created
ScaffoldExample()
}
}
}
}
现在运行应用程序并查看它的运行情况。
完整代码:
科特林
package com.gfg.scaffoldjetpackcompose
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Surface(color = Color.White) {
// Scaffold we created
ScaffoldExample()
}
}
}
}
@Composable
fun ScaffoldExample() {
// create a scaffold state, set it to close by default
val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Closed))
// Create a coroutine scope. Opening of Drawer
// and snackbar should happen in background
// thread without blocking main thread
val coroutineScope = rememberCoroutineScope()
// Scaffold Composable
Scaffold(
// pass the scaffold state
scaffoldState = scaffoldState,
// pass the topbar we created
topBar = {
TopBar(
// When menu is clicked open the
// drawer in coroutine scope
onMenuClicked = {
coroutineScope.launch {
// to close use -> scaffoldState.drawerState.close()
scaffoldState.drawerState.open()
}
})
},
// pass the bottomBar we created
bottomBar = { BottomBar() },
// Pass the body in
// content parameter
content = {
Body()
},
// pass the drawer
drawerContent = {
Drawer()
},
floatingActionButton = {
// Create a floating action button in
// floatingActionButton parameter of scaffold
FloatingActionButton(
onClick = {
// When clicked open Snackbar
coroutineScope.launch {
when (scaffoldState.snackbarHostState.showSnackbar(
// Message In the snackbar
message = "Snack Bar",
actionLabel = "Dismiss"
)) {
SnackbarResult.Dismissed -> {
// do something when
// snack bar is dismissed
}
SnackbarResult.ActionPerformed -> {
// when it appears
}
}
}
}) {
// Simple Text inside FAB
Text(text = "X")
}
}
)
}
// A function which will receive a
// callback to trigger to opening the drawer
@Composable
fun TopBar(onMenuClicked: () -> Unit) {
// TopAppBar Composable
TopAppBar(
// Provide Title
title = {
Text(text = "Scaffold||GFG", color = Color.White)
},
// Provide the navigation Icon ( Icon on the left to toggle drawer)
navigationIcon = {
Icon(
imageVector = Icons.Default.Menu,
contentDescription = "Menu",
// When clicked trigger onClick
// Callback to trigger drawer open
modifier = Modifier.clickable(onClick = onMenuClicked),
tint = Color.White
)
},
// background color of topAppBar
backgroundColor = Color(0xFF0F9D58)
)
}
@Composable
fun BottomBar() {
// BottomAppBar Composable
BottomAppBar(
backgroundColor = Color(0xFF0F9D58)
) {
Text(text = "Bottom App Bar", color = Color.White)
}
}
@Composable
fun Body() {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
Text(text = "Body Content", color = Color(0xFF0F9D58))
}
}
@Composable
fun Drawer() {
// Column Composable
Column(
Modifier
.background(Color.White)
.fillMaxSize()
) {
// Repeat is a loop which
// takes count as argument
repeat(5) { item ->
Text(text = "Item number $item", modifier = Modifier.padding(8.dp), color = Color.Black)
}
}
}
输出:
从 GitHub 获取完整的项目。