Scaffold in Android using Jetpack Compose
There are a lot of apps that contain TopAppBar, Drawer, Floating Action Button, BottomAppBar (in the form of bottom navigation), Snackbar. While you can individually set up all of these in an app but takes a lot of setups. Jetpack Compose provides Scaffold Composable which can save a lot of time. It’s like a prebuilt template. In this article, we will see how to set up Scaffold in android with Jetpack Compose. We will be building a basic app that will demonstrate the Scaffold composable, here is a video showing the app.
Prerequisites:
- Knowledge of Kotlin.
- Knowledge of Jetpack Compose.
Step by Step Implementation
Step 1: Creating TopAppBar
Open MainActivity.kt and create a TopBar Composable function, It will be a wrapper for our TopAppBar in Scaffold.
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 ) ) } |
Step 2: Create BottomAppBar
Open MainActivity.kt and create a BottomBar Composable. It will be a simple straight forward in our app.
Kotlin
@Composable fun BottomBar() { // BottomAppBar Composable BottomAppBar( backgroundColor = Color( 0xFF0F9D58 ) ) { Text(text = "Bottom App Bar" , color = Color.White) } } |
Step 3: Create Drawer content
Open MainActivity.kt and create a composable Drawer, It will be the drawer in our Scaffold.
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) } } } |
Step 4: Creating Body part of Scaffold
Create another composable function Body. It will be a simple Text composable in our app. Be sure to customize it when implementing it in other apps.
Kotlin
@Composable fun Body() { Column( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier .fillMaxSize() .background(Color.White) ) { Text(text = "Body Content" , color = Color( 0xFF0F9D58 )) } } |
Since all the components we need are done, let’s work on the Scaffold Part.
Step 5: Working with Scaffold
Since we have already created all the components, the Scaffold code will be pretty simple and self-explanatory.
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" ) } } ) } |
Now call this composable from setContent in Mainactivity class
Kotlin
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super .onCreate(savedInstanceState) setContent { Surface(color = Color.White) { // Scaffold we created ScaffoldExample() } } } } |
Now run the app and see it working.
Complete code:
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) } } } |
Output:
Get the complete project from GitHub.
Contact Us