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.
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()
}
}
- jetpack compose - TopAppBar center title
- jetpack compose - TopAppBar menu
- jetpack compose - Scaffold with Drawer
- jetpack compose - Scaffold with Snackbar
- jetpack compose - TabRow custon indicator
- jetpack compose - Get primary language
- jetpack compose - Get screen orientation
- jetpack compose - Kotlinx serialization handle null values
- jetpack compose - Kotlinx serialization not encode null values
- jetpack compose - Kotlinx serialization encode to string
- jetpack compose - Count up flow by ViewModel
- jetpack compose flow - Room add remove update
- jetpack compose flow - Room implement search
- jetpack compose - ViewModel Room delete clear data
- compose glance - How to create app widget