Jetpack Compose: Open and close drawer in code

Introduction

In this Android example, we'll explore how to use Jetpack Compose to create a dynamic user interface that opens and closes a navigation drawer in response to user interactions. A navigation drawer is a commonly used UI component that slides in from the side, allowing easy access to various sections within an app. This example demonstrates a straightforward approach to handling a navigation drawer using Jetpack Compose, which is a modern toolkit that simplifies building native UI in Android applications with a declarative approach.

The code in this example is organized to provide a seamless experience for managing the drawer state through simple buttons and icons. By utilizing coroutines to manage asynchronous actions, it offers smooth transitions for opening and closing the drawer. We'll go through each part of the code, breaking down how the components work together and how coroutine scopes are utilized to interact with the drawer.

Setting Up the Main Activity

The MainActivity class is the starting point of this example. It extends AppCompatActivity and overrides the onCreate method to set up the content view using the setContent function, a standard way to use Jetpack Compose in an activity. Within setContent, it calls the composable function GetScaffold, which sets up the entire structure of the UI, including the scaffold, top app bar, main content, and drawer.

The GetScaffold composable function is a key part of this structure. Here, the Scaffold composable provides a flexible container that manages the layout for top-level application components, like the top bar, main content area, and navigation drawer. By creating a ScaffoldState with rememberScaffoldState, the function manages the drawer’s state (open or closed) and links it to the drawer content, enabling control over its appearance.

Implementing the Drawer Content

The DrawerContent composable is responsible for the layout and behavior within the drawer. It uses a Box with padding and alignment modifiers to center the content. Inside the box, there's a TextButton labeled “Close Drawer.” When clicked, it triggers a coroutine that closes the drawer by setting its state to Closed via scaffoldState.drawerState.close(). This part uses the rememberCoroutineScope to initiate the coroutine, ensuring the drawer state changes smoothly and asynchronously.

The drawer’s appearance is further customized within GetScaffold by setting properties like drawerBackgroundColor, drawerScrimColor, drawerContentColor, and drawerShape. These properties define the background color, scrim (overlay) color when the drawer is open, content color inside the drawer, and the shape of the drawer itself, respectively. In this example, a CutCornerShape with 45.dp corner cuts on the top and bottom ends gives the drawer a unique, angled edge.

Configuring the Top App Bar

The TopAppBarContent composable provides a top bar with a title and a menu icon that opens the drawer. The TopAppBar composable takes a title parameter, which displays “Compose - Open Close Drawer” as a Text component, and a navigation icon parameter, which is an IconButton with a menu icon. When the icon is clicked, it opens the drawer by launching a coroutine with scaffoldState.drawerState.open(), similar to the close action in the drawer content.

Using a custom background color for the top bar (Color(0xFFC0E8D5)), this composable provides a cohesive look that aligns with the drawer’s style. The IconButton and Icon components used here demonstrate Jetpack Compose’s approach to handling icons and buttons within the UI, ensuring that both are functional and visually integrated with the rest of the application.

Building the Main Content

The MainContent composable sets up the primary content area of the screen. It features a Button in the center, labeled “Open Drawer,” which, when pressed, triggers the same coroutine-based drawer open action as the navigation icon in the top bar. This composable makes use of a Box to align the button at the center of the screen, creating a minimalist layout that draws attention to the drawer interaction.

The MainContent composable provides users with an alternative way to open the drawer, demonstrating flexibility in user interface design by enabling multiple access points for drawer functionality.

Adding a Preview Function

Finally, the ComposablePreview function serves as a placeholder for previewing the composable in Android Studio. Although it doesn’t render any content in this example (as GetScaffold is commented out), this function can be used for testing the UI layout during development without running the app on an emulator or physical device.

Summary

This example demonstrates the fundamentals of setting up a navigation drawer in Jetpack Compose and provides multiple ways to interact with it using coroutines. Through the use of composables like Scaffold, TopAppBar, Box, and buttons, the example showcases the declarative approach of Jetpack Compose for building responsive and clean UI layouts. With coroutine support, it also enables smooth drawer state transitions, enhancing user experience.

Overall, this code offers a straightforward approach to building a drawer-based UI in Jetpack Compose. It combines custom styling, coroutine-driven actions, and modular composables to create an adaptable and user-friendly interface. This example can be a great foundation for developers looking to implement drawers in their applications with minimal code and modern Android development practices.


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.foundation.shape.CutCornerShape
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.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch


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


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

        Scaffold(
            scaffoldState = scaffoldState,
            topBar = { TopAppBarContent(scaffoldState) },
            content = {MainContent(scaffoldState)},
            backgroundColor = Color(0xFFEDEAE0),
            drawerContent = {DrawerContent(scaffoldState)},
            drawerBackgroundColor = Color(0xFFF0F8FF),
            drawerScrimColor = Color(0XFFFAE7B5),
            drawerContentColor = Color(0xFF0048BA),
            drawerShape = CutCornerShape(
                topEnd = 45.dp,
                bottomEnd = 45.dp
            )
        )
    }


    @Composable
    fun DrawerContent(scaffoldState: ScaffoldState){
        val scope = rememberCoroutineScope()
        Box(
            modifier = Modifier.padding(12.dp),
            contentAlignment = Alignment.TopCenter
        ) {
            TextButton(onClick = {
                scope.launch{
                    scaffoldState.drawerState.close()
                }
            }) {
                Text(text = "Close Drawer")
            }
        }
    }


    @Composable
    fun TopAppBarContent(scaffoldState: ScaffoldState) {
        val scope = rememberCoroutineScope()
        TopAppBar(
            title = { Text(text = "Compose - Open Close Drawer")},
            backgroundColor = Color(0xFFC0E8D5),

            navigationIcon = {
                IconButton(onClick = {
                    scope.launch{
                        scaffoldState.drawerState.open()
                    }
                }) {
                    Icon(
                        Icons.Filled.Menu,
                        contentDescription = "Localized description"
                    )
                }
            }
        )
    }


    @Composable
    fun MainContent(scaffoldState: ScaffoldState){
        val scope = rememberCoroutineScope()
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ){
            Button(onClick = {
                scope.launch{
                    scaffoldState.drawerState.open()
                }
            }) {
                Text(text = "Open Drawer")
            }
        }
    }


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