Jetpack Compose: TopAppBar navigation

Introduction

In this Kotlin-based Android application example, we demonstrate how to use Jetpack Compose to create a TopAppBar navigation within a Scaffold. Jetpack Compose simplifies Android UI development by leveraging a declarative approach, which is different from the traditional XML layouts used in Android development. By using Composable functions, we can build UI components in a way that makes them easily reusable and highly customizable. This example creates a basic structure with a top navigation bar, a drawer that slides out from the left, and main content in the center of the screen.

The goal of this tutorial is to walk through the main components of the example code, explaining the purpose of each part and how it fits into the overall structure. By the end, you’ll have a clearer understanding of how to use TopAppBar, Scaffold, and Jetpack Compose’s composable functions to create a structured and visually appealing layout.

Breakdown of MainActivity.kt: Setting up the Main Activity and Scaffold

In the MainActivity class, we override the onCreate function and set up the main content of our activity using setContent { GetScaffold() }. This function call triggers the GetScaffold composable, which contains the primary layout structure. The @ExperimentalMaterialApi annotation is used here because certain components, like the Scaffold’s drawer, are marked as experimental and may change in future releases.

The GetScaffold function starts by creating a ScaffoldState, which controls the state of the drawer (whether it's open or closed). The rememberScaffoldState function initializes this state with a DrawerValue.Closed value, indicating that the drawer is initially closed. This state management is essential for handling user interactions with the drawer.

Defining the Scaffold and Its Properties

Within the GetScaffold function, we define a Scaffold composable that serves as the main container for the app layout. The Scaffold component allows us to specify multiple regions, including the top bar, content area, and drawer. Here, the topBar parameter calls TopAppBarContent to set up the top navigation bar, and the content parameter calls MainContent to place the main content at the center of the screen.

The Scaffold composable also supports additional parameters, such as backgroundColor and drawerContent. Here, backgroundColor is set to a light beige shade (Color(0xFFEDEAE0)), which gives a warm look to the layout. For the drawerContent, a simple Text composable displays "Drawer Content," and drawerBackgroundColor is set to a soft cream color (Color(0xFFE3DAC9)). These color settings showcase how you can easily customize the look and feel of the layout using color codes.

Creating the TopAppBar with Navigation Icon

The TopAppBarContent composable sets up a top app bar that includes a navigation icon and title. The ScaffoldState is passed as a parameter to control the drawer’s open/close state. We use TopAppBar, a material design component, for creating a consistent top bar across screens. The TopAppBar has a title parameter where a Text composable displays "Compose - TopAppBar Navigation."

The navigationIcon parameter adds a menu icon button that, when clicked, opens the drawer. The IconButton wraps an Icon, which is the actual visual element displaying the menu icon. To handle the drawer’s open/close state, we create a coroutine scope with rememberCoroutineScope. This coroutine allows us to asynchronously open the drawer by calling scaffoldState.drawerState.open() when the icon button is pressed.

Centering the Main Content

The MainContent composable displays the main content of the app. This content is centered using a Box with Modifier.fillMaxSize() to occupy the entire screen and contentAlignment = Alignment.Center. Inside this Box, a Text composable displays "Main Content" in a larger font, using MaterialTheme.typography.h5 for styling. This setup demonstrates how to center content and apply styling using Jetpack Compose’s typography.

Previewing the Composables

Finally, the ComposablePreview function provides a preview of the layout in Android Studio’s Preview pane. However, GetScaffold is commented out in the preview function, which prevents it from being rendered. Typically, uncommenting this line would allow developers to preview the UI directly in Android Studio, enabling them to see how the composable functions render without having to deploy the app to an emulator or device.

Summary

This example demonstrates how to use Jetpack Compose to create a simple but structured layout with a TopAppBar, a main content area, and a drawer for navigation. By using composable functions such as TopAppBar, Scaffold, and Box, the code leverages Jetpack Compose’s declarative approach, making it easy to organize and customize UI components. This structure can serve as a foundation for more complex navigation and layout designs, making it suitable for scalable Android applications.

The use of coroutine scopes and state management within Scaffold adds flexibility for handling user interactions and provides a smoother user experience. With Jetpack Compose, Android developers can create UI components in a more intuitive way, leading to cleaner code and faster development times.


MainActivity.kt

package com.cfsuman.jetpackcompose

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch


class MainActivity : AppCompatActivity() {
    @ExperimentalMaterialApi
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            GetScaffold()
        }
    }


    @ExperimentalMaterialApi
    @Composable
    fun GetScaffold(){
        val scaffoldState:ScaffoldState = rememberScaffoldState(
            rememberDrawerState(DrawerValue.Closed)
        )

        Scaffold(
            scaffoldState = scaffoldState,
            topBar = { TopAppBarContent(scaffoldState) },
            content = {MainContent()},
            backgroundColor = Color(0xFFEDEAE0),
            drawerContent = { Text(
                text = "Drawer Content",
                Modifier.padding(12.dp)
            )},
            drawerBackgroundColor = Color(0xFFE3DAC9)
        )
    }


    @ExperimentalMaterialApi
    @Composable
    fun TopAppBarContent(scaffoldState: ScaffoldState) {
        val scope = rememberCoroutineScope()

        TopAppBar(
            title = { Text(text = "Compose - TopAppBar Navigation")},
            backgroundColor = Color(0xFFC0E8D5),
            navigationIcon = {
                IconButton(
                    onClick = { scope.launch {
                        scaffoldState.drawerState.open() }
                    })
                {
                    Icon(
                        Icons.Filled.Menu,
                        contentDescription = "Localized Description"
                    )
                }
            }
        )
    }


    @Composable
    fun MainContent(){
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ){
            Text(
                text = "Main Content",
                style = MaterialTheme.typography.h5
            )
        }
    }


    @Preview
    @Composable
    fun ComposablePreview(){
        //GetScaffold()
    }
}
More android jetpack compose tutorials