Step-by-Step: Build a Toolbar Menu with Jetpack Compose

Jetpack Compose has revolutionized Android UI development by introducing a declarative approach to building user interfaces. One essential feature of most mobile apps is a toolbar menu. In this tutorial, we will walk through creating a fully functional toolbar menu using Jetpack Compose, showcasing best practices and advanced techniques to elevate your app's user experience.

Prerequisites

Before diving into the implementation, ensure you have:

  • A basic understanding of Jetpack Compose.

  • Android Studio Bumblebee (or later) installed.

  • Kotlin programming knowledge.

Now, let’s get started!

1. Setting Up the Project

If you’re starting a new project, create one with Jetpack Compose enabled:

  1. Open Android Studio.

  2. Select File > New Project.

  3. Choose Empty Compose Activity and click Next.

  4. Configure your project settings and ensure Use Jetpack Compose is checked.

If you’re adding Compose to an existing project, ensure the following dependencies are in your build.gradle file:

implementation "androidx.compose.ui:ui:1.x.x"
implementation "androidx.compose.material:material:1.x.x"
implementation "androidx.compose.ui:ui-tooling-preview:1.x.x"
implementation "androidx.activity:activity-compose:1.x.x"
implementation "androidx.navigation:navigation-compose:2.x.x"

Sync your project after updating the dependencies.

2. Creating a Basic Toolbar with Jetpack Compose

Compose simplifies toolbar creation by using the TopAppBar component. Here’s how you can create a basic toolbar:

@Composable
fun BasicToolbar() {
    TopAppBar(
        title = {
            Text(text = "My Toolbar")
        },
        backgroundColor = MaterialTheme.colors.primary,
        contentColor = Color.White
    )
}

Key Parameters:

  • title: Displays the toolbar’s title.

  • backgroundColor: Sets the background color of the toolbar.

  • contentColor: Defines the color for content like text and icons.

3. Adding Menu Items to the Toolbar

To add a menu, we’ll use the IconButton and DropdownMenu components.

Step 1: Define Menu Items

First, create a sealed class to represent your menu options:

sealed class MenuOption(val title: String, val icon: ImageVector) {
    object Settings : MenuOption("Settings", Icons.Default.Settings)
    object Help : MenuOption("Help", Icons.Default.Help)
    object Logout : MenuOption("Logout", Icons.Default.ExitToApp)
}

Step 2: Implement the Menu

Now, add menu functionality to your toolbar:

@Composable
fun ToolbarWithMenu() {
    var expanded by remember { mutableStateOf(false) }

    TopAppBar(
        title = {
            Text(text = "My Toolbar")
        },
        actions = {
            IconButton(onClick = { expanded = true }) {
                Icon(Icons.Default.MoreVert, contentDescription = "Menu")
            }
            DropdownMenu(
                expanded = expanded,
                onDismissRequest = { expanded = false }
            ) {
                DropdownMenuItem(onClick = {
                    // Handle Settings click
                    expanded = false
                }) {
                    Icon(imageVector = MenuOption.Settings.icon, contentDescription = null)
                    Spacer(modifier = Modifier.width(8.dp))
                    Text(text = MenuOption.Settings.title)
                }
                DropdownMenuItem(onClick = {
                    // Handle Help click
                    expanded = false
                }) {
                    Icon(imageVector = MenuOption.Help.icon, contentDescription = null)
                    Spacer(modifier = Modifier.width(8.dp))
                    Text(text = MenuOption.Help.title)
                }
                DropdownMenuItem(onClick = {
                    // Handle Logout click
                    expanded = false
                }) {
                    Icon(imageVector = MenuOption.Logout.icon, contentDescription = null)
                    Spacer(modifier = Modifier.width(8.dp))
                    Text(text = MenuOption.Logout.title)
                }
            }
        },
        backgroundColor = MaterialTheme.colors.primary,
        contentColor = Color.White
    )
}

4. Advanced Techniques and Customizations

Custom Toolbar Styles

You can further customize your toolbar by:

  • Adding navigation icons.

  • Applying elevation for a shadow effect.

  • Using gradients for the background.

Example with a navigation icon:

@Composable
fun ToolbarWithNavigation(onNavigationClick: () -> Unit) {
    TopAppBar(
        title = {
            Text(text = "My Toolbar")
        },
        navigationIcon = {
            IconButton(onClick = onNavigationClick) {
                Icon(Icons.Default.ArrowBack, contentDescription = "Back")
            }
        },
        backgroundColor = MaterialTheme.colors.primary,
        contentColor = Color.White
    )
}

Dynamic Menu Items

For a dynamic list of menu items, use a List or LazyColumn inside the DropdownMenu:

@Composable
fun DynamicMenu(toolbarItems: List<MenuOption>, onItemClick: (MenuOption) -> Unit) {
    var expanded by remember { mutableStateOf(false) }

    TopAppBar(
        title = {
            Text(text = "Dynamic Toolbar")
        },
        actions = {
            IconButton(onClick = { expanded = true }) {
                Icon(Icons.Default.MoreVert, contentDescription = "Menu")
            }
            DropdownMenu(
                expanded = expanded,
                onDismissRequest = { expanded = false }
            ) {
                toolbarItems.forEach { item ->
                    DropdownMenuItem(onClick = {
                        onItemClick(item)
                        expanded = false
                    }) {
                        Icon(imageVector = item.icon, contentDescription = null)
                        Spacer(modifier = Modifier.width(8.dp))
                        Text(text = item.title)
                    }
                }
            }
        }
    )
}

5. Testing and Debugging Tips

Preview Your Toolbar

Leverage Compose Previews for faster iteration:

@Preview(showBackground = true)
@Composable
fun ToolbarPreview() {
    MaterialTheme {
        ToolbarWithMenu()
    }
}

Debugging Layout Issues

Use Modifier.debugInspectorInfo or Android Studio’s Layout Inspector to debug your toolbar’s layout.

Conclusion

Building a toolbar menu with Jetpack Compose is both efficient and flexible. By leveraging Compose’s declarative nature, you can create dynamic, highly customizable toolbars that enhance the user experience. Experiment with advanced techniques like dynamic menus and custom navigation to further refine your app’s UI.

Start integrating these practices into your projects, and stay ahead in the ever-evolving world of Android development!