Android Nomad #40 - Bottom sheets
Tips and tricks for implementing a Modal Bottom Sheet
Modal bottom sheets are versatile UI components that play a crucial role in modern app design. They're commonly used to display secondary actions, settings, or additional content without navigating away from the current screen.
Understanding Modal Bottom Sheets
Modal bottom sheets appear in response to user actions, such as tapping a button or an overflow icon. They can be dismissed through various means:
- Selecting a menu item or action within the bottom sheet
- Tapping the scrim (the semi-transparent overlay)
- Swiping the sheet down
- Using a close affordance (e.g., a close button) in the sheet's top app bar, if present
Key Considerations for Implementation
When implementing a modal bottom sheet, there are three primary aspects to consider:
- Design: Ensure your UI adheres to Material 3 guidelines, including the use of a drag handle or close button.
- State Management: Properly manage the bottom sheet's state for smooth interactions.
- Dismiss Handling: Carefully manage dismiss actions to avoid focus-related issues.
Let's dive deeper into each of these aspects.
Implementing Modal BottomSheet in Compose
1. BottomSheetState
val bottomSheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = false,
confirmValueChange = { true }
) skipPartiallyExpanded: Whentrue, the sheet will always fully expand or hide, skipping the partially expanded state. Set tofalseto allow partial expansion based on content height.confirmValueChange: This optional parameter allows you to handle state changes. The default implementation always returnstrue, but you can customize it for more granular control.
2. ModalBottomSheet
ModalBottomSheet(
onDismissRequest = { openBottomSheet = false },
sheetState = bottomSheetState
) {
// Your bottom sheet content goes here
}
onDismissRequest: This callback is triggered when the user attempts to dismiss the sheet (e.g., by tapping outside). It's crucial for managing the sheet's visibility.
3. Handling dismiss
Proper dismiss handling is essential to avoid UI glitches. Here's a recommended approach:
val scope = rememberCoroutineScope()
// When dismissing the bottom sheet
scope.launch {
bottomSheetState.hide()
}.invokeOnCompletion {
if (!bottomSheetState.isVisible) {
openBottomSheet = false
}
}This pattern ensures that the openBottomSheet state is only updated after the bottom sheet has fully hidden, preventing potential race conditions.
Finally, I highly recommend reading the material guidelines, it is a well written document which covers almost everything you need to know for designing a comprehensive modal bottom sheet.