MapBottomSheet
The MapBottomSheet is a custom bottom sheet built with AnchoredDraggable (not Material's BottomSheetScaffold) for full control over anchor positions and nested scroll behavior. For the rationale behind this choice, see the design decisions.
SheetAnchor State Machineβ
enum class SheetAnchor {
Collapsed,
HalfExpanded,
Expanded,
}
Anchor positions are computed from the available height:
| Anchor | Offset (from top) | Description |
|---|---|---|
Collapsed | availableHeight - dragHandleHeight | Only the drag handle visible (24dp) |
HalfExpanded | availableHeight * (1 - 0.50) | 50% of screen (or content-fitted for detail views) |
Expanded | availableHeight * (1 - 0.90) | 90% of screen |
For fixed-height content (device info, notification info), HalfExpanded snaps to the actual content height instead of 50%:
val halfOffset = if (isFixedContent && measuredContentHeight > 0) {
val contentSheetHeight = measuredContentHeight + collapsedHeightPx
(availableHeightPx - contentSheetHeight).coerceAtLeast(expandedOffset)
} else {
availableHeightPx * (1f - Dimensions.BottomSheet.HALF_FRACTION)
}
BottomSheet Dimension Tokensβ
| Token | Value |
|---|---|
dragHandleHeight | 24.dp |
dragHandleWidth | 28.dp |
dragHandleThickness | 3.dp |
topCornerRadius | 16.dp |
headerHeight | 40.dp |
EXPANDED_FRACTION | 0.90f |
HALF_FRACTION | 0.50f |
Nested Scroll Integrationβ
The BottomSheetNestedScrollConnection coordinates between the sheet's drag and the inner LazyColumn scroll:
// Swiping up: only move sheet if Collapsed
dy < 0 -> sheetState.currentValue == SheetAnchor.Collapsed
// Swiping down: collapse sheet when list is at top
dy > 0 -> !lazyListState.canScrollBackward
Fling behavior:
- Fling up from Collapsed β animate to
HalfExpanded - Fling up at HalfExpanded (list can't scroll further) β animate to
Expanded - Fling down (list at top) β step down one anchor (
ExpandedβHalfExpandedβCollapsed)
SheetContentModeβ
The sheet supports three content modes via a sealed class:
sealed class SheetContentMode {
data object DeviceList : SheetContentMode()
data class DeviceInfo(val device: DeviceWithPosition) : SheetContentMode()
data class NotificationInfo(val detail: NotificationDetail, val deviceName: String) : SheetContentMode()
}
Content transitions use AnimatedContent with fadeIn togetherWith fadeOut. When switching to DeviceInfo or NotificationInfo, the sheet auto-animates to HalfExpanded.