Jetpack Compose: Getting Started

Aug 1 2023 · Kotlin 1.8.10, Android 13, Android Studio Flamingo

Part 3: Jetpack Controls

15. Using a Scaffold Layout

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 14. Challenge: Add Trailing & Leading Icons to TextField Next episode: 16. Display Lists Using Lazy Layouts

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 15. Using a Scaffold Layout

Design systems are a collection of reusable components, guided by clear standards, that can be assembled together to build any number of applications with less time and effort.

In Android, we have the Material Design system. Material Design was created by Google in 2014, it offers a system for building bold, beautiful, and consistent digital products. It is a system that helps teams build high-quality digital experiences for Android, iOS, Flutter, and the web.

The current version of Material Design is Material Design 3 which was announced at Google I/O 2021. Material Design 3 is a major update to the Material Design system.

Material Design 3 has a host of different components that we can use to build our apps. This components have their equivalent Composables. Some of these components include:

  • Buttons
  • Cards
  • Chips
  • Dialogs
  • TextFields
  • etc.

We have already looked at a few of these components in the previous sessions. In this session, we will look at a few more components. All these components are availble by opting into the material library.

A card is a sheet of material that serves as an entry point to more detailed information. Cards may contain a photo, text, and a link about a single subject. They may display content containing elements of varying size, such as photos with captions of variable length.

In Jetpack Compose, we can use the Card Composable to create a card. The Card Composable is part of the material library.

Card is a surface with a background color and elevation. It can be used to display content in a contained space.

It has one Mandatory parameter:

  • onClick: This is used to specify the action to take when the card is clicked. It is of type () -> Unit and has no default value.

It has several optional parameters:

  • colors: This is used to specify the colors to use for the card. It is of type CardColors and has a default value of CardDefaults.colors().
  • shape: This is used to specify the shape of the card. It is of type Shape.
  • border: This is used to specify the border of the card. It is of type BorderStroke.
  • elevation: This is used to specify the elevation of the card. It is of type Elevation.
  • content: This is used to specify the content of the card. It is of type @Composable ColumnScope.() -> Unit and will be called to draw the content of the card. All the items inside the content block will be placed inside the card vertically since they will be in a ColumnScope.

Create a Card

Let us wrap our search TextField in a Card Composable.

@ExperimentalMaterial3Api
@Composable
fun SearchBar() {

    Card(
        modifier = Modifier
            .fillMaxWidth()
            .height(75.dp)
            .padding(end = 16.dp, start = 16.dp, top = 10.dp),
        shape = RoundedCornerShape(100.dp),
    ) {

        TextField(
            modifier = Modifier.fillMaxSize(),
            value = "",
            onValueChange = { "" },
            leadingIcon = { Image(painter = painterResource(id = R.drawable.ic_search), contentDescription = "search bar") },
            trailingIcon = { Image(painter = painterResource(id = R.drawable.ic_filter), contentDescription = "filter") },
            placeholder = {
                Text(
                    text = "Search for food ...",
                    modifier = Modifier
                        .fillMaxHeight(),
                    textAlign = TextAlign.Center,
                )
            },
            colors = TextFieldDefaults.textFieldColors(
                focusedIndicatorColor = Color.Transparent,
                unfocusedIndicatorColor = Color.Transparent,
            ),
        )
    }
}

Floating Action Button

A floating action button (FAB) is a circular button that triggers the primary action in your app’s UI. This button floats above the content of the screen and usually resides on one corner of the screen.

In Jetpack Compose, we can use the FloatingActionButton Composable to create a floating action button.

The FloatingActionButton has one Mandatory parameter:

  • onClick: This is used to specify the action to take when the floating action button is clicked. It is of type () -> Unit and has no default value.

Several other optional arguments are available:

  • containerColor: This is used to specify the background color of the floating action button. It is of type Color and has a default value of MaterialTheme.colors.primary.
  • contentColor: This is used to specify the color of the content of the floating action button. It is of type Color and has a default value of MaterialTheme.colors.onPrimary.
  • elevation: This is used to specify the elevation of the floating action button. It is of type Elevation and has a default value of Elevation.Medium.
  • shape: This is used to specify the shape of the floating action button. It is of type Shape and has a default value of CircleShape.

Add a Floating Action Button

Let us refactor our FoodItem Composable to use a FloatingActionButton instead of a Button.

@Composable
fun FoodItem(
    food: Food,
    id: Int = 0,
) {

    Card(
        modifier = Modifier
            .width(200.dp)
            .clickable {

            }
            .padding(end = 8.dp),
        shape = RoundedCornerShape(corner = CornerSize(10.dp))) {

        Column(modifier = Modifier
            .padding(bottom = 5.dp)
            .fillMaxWidth()) {

            Image(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(150.dp),
                painter = painterResource(id = food.banner),
                contentDescription = "image",
                contentScale = ContentScale.Crop
            )

            Spacer(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(8.dp))

            Column(
                modifier = Modifier
                    .padding(horizontal = 5.dp)
                    .fillMaxWidth()) {

                Text(
                    modifier = Modifier,
                    text = food.name,
                    style = MaterialTheme.typography.bodyLarge,
                    fontStyle = FontStyle.Normal,
                    fontWeight = FontWeight.ExtraBold)
                
                Row(
                    modifier = Modifier
                        .padding(top = 5.dp),
                    verticalAlignment = Alignment.CenterVertically) {
                    
                    Image(
                        painter = painterResource(id = R.drawable.ic_clock),
                        contentDescription = "Clock",
                        colorFilter = ColorFilter.tint(
                            color = MaterialTheme.colorScheme.onBackground
                        )
                    )

                    Text(
                        modifier = Modifier.padding(start = 3.dp),
                        text = "${food.waitTime} mins",
                        style = MaterialTheme.typography.bodySmall)

                }

                Spacer(modifier = Modifier
                    .height(2.dp))

                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(horizontal = 4.dp),
                    horizontalArrangement = Arrangement.SpaceBetween,
                    verticalAlignment = Alignment.CenterVertically) {

                    Text(
                        text = "$${food.originalPrice}",
                        fontWeight = FontWeight.ExtraBold,
                        style = MaterialTheme.typography.bodyLarge
                    )
                    
                    FloatingActionButton(
                        onClick = { /*TODO*/ },
                        shape = CircleShape,
                        containerColor = MaterialTheme.colorScheme.tertiary) {
                        Image(
                            painter = painterResource(id = R.drawable.ic_add),
                            contentDescription = "Add",
                            colorFilter = ColorFilter.tint(
                                color = contentColorFor(MaterialTheme.colorScheme.tertiary)))
                    }

                }

            }


        }

    }

}

Scaffold Layout

The Scaffold Composable is a layout component that implements the basic material design visual layout structure. It is used to implement the top-level structure of a screen in your app.

The Scaffold Composable provides slots for the following:

  1. App Bars App Bars are used to display information and actions relating to the current screen. They can be placed at the top or bottom of the screen. The Scaffold Composable provides a slot for the top app bar and the bottom app bar.

    • topBar: This is used to specify the top app bar. It is of type @Composable () -> Unit and has no default value.
    • bottomBar: This is used to specify the bottom app bar. It is of type @Composable () -> Unit and has no default value.
  2. Floating Action Button Floating action buttons are used to trigger the primary action in your app’s UI. The Scaffold Composable provides a slot for the floating action button.

    • floatingActionButton: This is used to specify the floating action button. It is of type @Composable () -> Unit and has no default value.
  3. content The content slot is used to specify the content of the screen. It is of type @Composable (PaddingValues) -> Unit and has no default value.

    The PaddingValues parameter is used to specify the padding to apply to the content. It is of type PaddingValues and has a default value of PaddingValues(0.dp).

  4. Drawer The drawer slot is used to specify the drawer of the screen. It is of type @Composable () -> Unit and has no default value.

  5. Snackbars Snackbars are used to display brief messages to the user. The Scaffold Composable provides a slot for the snackbar.

    • snackbarHost: This is used to specify the snackbar. It is of type @Composable () -> Unit and has no default value.

Add a Scaffold Layout

@Preview(showBackground = true)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeScreen() {
  Scaffold(
      modifier = Modifier.fillMaxSize(),
      topBar = { ProfileBar() },
      bottomBar = {
        Text(text = "Bottom Bar")
      }){ paddingValues ->
            Column(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(paddingValues = paddingValues),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally,
            ){
              Text(text = "Home Screen")
            }
  }
}

Conclusion

In this lesson, we have looked at how to implement a few other Material 3 components into our application. We have also got a better understanding of how the Scaffold Layout works.

In our next episode we will look at how to display a list of items on the screen using lazy layouts.