avatarAndroidAI

Summary

The blog post discusses the implementation of a Material 3 bottom sheet with a drag handle in Jetpack Compose, addressing common issues and providing code examples for developers.

Abstract

The article introduces the concept of Material 3 bottom sheets with drag handles in Jetpack Compose, highlighting the importance of adhering to the latest design guidelines for a better user interface and experience. It walks through the process of setting up the necessary dependencies, designing the user interface, and writing the composable functions in Kotlin. The author shares their experience with a specific issue related to the default drag handle UI and offers a solution to customize or remove the drag handle. Code snippets are provided to illustrate how to create a custom bottom sheet, manage its state, and implement a custom drag handle or opt-out of using one. The post aims to assist Android developers in leveraging the new components and guidelines provided by Material 3 to streamline their development process and enhance UI design.

Opinions

  • The author believes that the new Material 3 design guidelines and components can significantly improve the user interface and experience.
  • They acknowledge the challenge faced by developers in dealing with the default drag handle UI in Material 3 bottom sheets.
  • The author suggests that understanding and utilizing the experimental Material 3 APIs is crucial for developers to achieve the desired UI components in Jetpack Compose.
  • They emphasize the importance of customization options for the drag handle, providing developers with the flexibility to align with their specific design requirements.
  • The post reflects the author's dedication to sharing practical insights and solutions with the developer community, as evidenced by their detailed analysis and code examples.
  • The author encourages reader engagement and feedback, indicating a collaborative approach to problem-solving and knowledge sharing within the Android development community.

Material 3 bottom sheet — DragHandle Jetpack compose

Hello everyone, hope everybody is fine. In this blog, we are going to see about the latest Material 3 bottom sheet design with a drag handle in Jetpack compose. Let us start

Many Android developer knows about Material Design which is a design system for Android that mostly contains about different components, guidelines, specifications, accessibility, etc. The Material team released Material 3 which contains the latest design guidelines, components, etc using which we can develop better UI to make a better user experience for wide users. The Android team will create a component with guidelines and specs of material design in XML which as a developer we can use it. Now you all know Jetpack compose is a new UI toolkit for Android they will introduce the components which achieve all guidelines of material design and release so as a developer we can use it also which reduce our work. So I thought we will use the latest bottom sheet of material 3 and play with it.

I think many know how to create a bottom sheet using Jetpack Compose which is not new. Here I am going to explain the small issue I faced while creating a Material 3 bottom sheet. Okay, no more theory let us go inside the practical.

Dependency

implementation "androidx.compose.material3:material3:1.1.0"

UI

As this blog aims at the main issue we are not going to explain much about the UI of Bottomsheet. This bottom sheet is a theme selection bottom sheet nothing more. Here is the UI

Code

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomBottomSheet() {

    ModalBottomSheet(modifier = Modifier, sheetState = rememberModalBottomSheetState(
        skipPartiallyExpanded = false), onDismissRequest = {
    }, shape = RoundedCornerShape(
        topStart = 10.dp,
        topEnd = 10.dp
    ),
    ) {
        CustomBottomSheetContainer()
    }
}

Here are going to use the ModalBottomSheet of Material 3.

Note: This API is experimental

ModalBottomSheet: This is a built-in Jetpack Compose component used to display a modal bottom sheet. It takes several parameters

  • sheetState: This parameter represents the state of the bottom sheet, and it is created using rememberModalBottomSheetState. The skipPartiallyExpanded property is set to false, which means the bottom sheet can partially expand instead of immediately closing when dragged upwards.
  • onDismissRequest: This is a callback function that is triggered when the user tries to dismiss the bottom sheet. In our code, it is left empty.
  • shape: This parameter is used to define the shape of the bottom sheet. In your code, it is set to a RoundedCornerShape with topStart and topEnd corners having a radius of 10.dp.

We have created the CustomBottomSheetContainer function which will be the content of the bottom sheet.

@Composable
fun CustomBottomSheetContainer() {
    Scaffold(topBar = {
        Column {
            Text(text = "Theme", modifier = Modifier.height(75.dp)
                    .padding(start = 29.dp, top = 26.dp),fontSize = 23.sp)
            Divider(color = Color.Black, thickness = 1.dp)
        }
    }) {
        Column(modifier = Modifier.padding(it)) {
            Text(text = "Select theme", modifier = Modifier
                    .padding(start = 29.dp, top = 20.dp, bottom = 10.dp)
                    .height(40.dp),fontSize = 20.sp)
            CustomItem("Light")
            CustomItem("Dark")
            CustomItem("System default")
        }
    }
}

Here we have created the bottom sheet content called CustomBottomSheetContainer

Here's a breakdown of the code:

Scaffold: This is a built-in Jetpack Compose component used to implement the basic structure of a screen. It provides a top app bar and other common UI elements. It takes the following parameters:

  • topBar: This parameter defines the content of the top app bar. It consists of a Column composable that contains a Text composable displaying the text "Theme" and a Divider composable below it.

Column: This is a composable function used to vertically stack multiple elements.

1. Text: This is a composable function used to display text. The first one displays the text “Select theme” and applies padding and height using the Modifier parameter.

2. Second one is CustomRadioButtonItem which is the item that will be displayed on the bottom sheet.

Overall, the CustomBottomSheetContainer the composable function sets up a basic layout using Jetpack Compose Scaffold and Column components. It displays a top app bar with the "Theme" text and a divider. Below the top app bar, it displays the "Select theme" text and presumably renders multiple radio button items using the CustomRadioButtonItem composable function.

@Composable
fun CustomItem(text: String) {
    Row(modifier = Modifier.height(40.dp), verticalAlignment = Alignment.CenterVertically) {
        Image(
            painter = painterResource(id = R.drawable.frame_1),
            modifier = Modifier.padding(start = 31.dp, top = 9.dp), contentDescription = ""
        )
        Text(
            text = text, modifier = Modifier
                .height(40.dp)
                .padding(start = 20.dp, top = 11.dp),
            fontSize = 18.sp
        )
    }
}

Here we have created the item for the bottom sheet

Overall, the CustomItem composable function creates a row with an image and text, representing a single image item. The image is displayed at the beginning of the row, and the text is displayed next to it, both with specified padding and height. The actual image resource used (R.drawable.frame_1) is not included in the code snippet you provided.

Now comes the issue as you can see in the image of the Bottom sheet UI you can see the cement color line. In the new design of the bottom sheet by default, they added a drag handle UI which is used for dragging. For me the UI is without a drag handle so analyzed the code of ModalBottomSheet how they have drawn and found that it uses dragHandle attribute which accepts null. DragHandle will be drawn if it is not null. You may ask if it accepts null means it should be drawn by default right? Here is the hack, by default dragHandle is not null the android team sets composable content for dragHandle by default. So to avoid this when you use modalBottomSheet of Material 3 please consider of passing null to dragHandle attribute. If you pass your custom dragHandle UI compose function as it accepts composable.

Here is the ModalBottomSheet code

In the image, you can see the dragHandle attribute which accepts null, and by default, it uses a default compose function

Without dragHandle

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomBottomSheet() {

    ModalBottomSheet(modifier = Modifier, sheetState = rememberModalBottomSheetState(
        skipPartiallyExpanded = false), onDismissRequest = {
    }, shape = RoundedCornerShape(
        topStart = 10.dp,
        topEnd = 10.dp
    ), dragHandle = null,
    ) {
        CustomBottomSheetContainer()
    }
}

If you do not want the dragHandle to pass null to attribute which won't draw the dragHandle

Custom DragHandle

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomBottomSheet() {

    ModalBottomSheet(
        modifier = Modifier,
        sheetState = rememberModalBottomSheetState(
            skipPartiallyExpanded = false
        ),
        onDismissRequest = {
        },
        shape = RoundedCornerShape(
            topStart = 10.dp,
            topEnd = 10.dp
        ),
        dragHandle = { Spacer(modifier = Modifier.width(30.dp).height(5.dp).background(Color.Red)) },
    ) {
        CustomBottomSheetContainer()
    }
}

Here I added The Spacer composable which will create a 30dp wide and 5dp high empty space with a red background color, that act as a divider

As you can see in the UI, it drew the spacer at the center horizontally but I didn't give any alignment. After analyzing the code of dragHandle by default it aligns the dragHandle content to center. Here is the screenshot

Conclusion

The many bottom sheet design won't contains dragHandle. I faced the issue and surfed the internet on how to disable it but no luck. So I read the bottom sheet compose code and found this. So I thought this will be very helpful for developers who faced issues like me.

Thank you for reading. Comment below if you have any suggestions, doubts, etc

Android
Android App Development
Jetpack Compose
Material Design
Bottomsheet
Recommended from ReadMedium
avatarNine Pages Of My Life
Flow Layouts in Jetpack Compose

🎯Index

4 min read