Class

AdaptStrategy.Levitate

Indicate the associated pane should be levitated when it's the current destination.

RevenueCat

RevenueCat

Add subscriptions to your apps in minutes

Ad Get started for free

ListDetailPaneScaffoldSampleWithExtraPaneLevitatedAsDialog

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Preview
@Composable
fun ListDetailPaneScaffoldSampleWithExtraPaneLevitatedAsDialog() {
    val coroutineScope = rememberCoroutineScope()
    val scaffoldNavigator = levitateAsDialogSample<NavItemData>()
    val items = listOf("Item 1", "Item 2", "Item 3")
    val extraItems = listOf("Extra 1", "Extra 2", "Extra 3")
    val selectedItem = scaffoldNavigator.currentDestination?.contentKey
    ListDetailPaneScaffold(
        directive = scaffoldNavigator.scaffoldDirective,
        scaffoldState = scaffoldNavigator.scaffoldState,
        listPane = {
            AnimatedPane(modifier = Modifier.preferredWidth(200.dp)) {
                ListPaneContent(
                    items = items,
                    selectedItem = selectedItem,
                    scaffoldNavigator = scaffoldNavigator,
                    coroutineScope = coroutineScope,
                )
            }
        },
        detailPane = {
            AnimatedPane {
                DetailPaneContent(
                    items = items,
                    selectedItem = selectedItem,
                    scaffoldNavigator = scaffoldNavigator,
                    hasExtraPane = true,
                    coroutineScope = coroutineScope,
                )
            }
        },
        extraPane = {
            AnimatedPane {
                ExtraPaneContent(
                    extraItems = extraItems,
                    selectedItem = selectedItem,
                    scaffoldNavigator = scaffoldNavigator,
                    coroutineScope = coroutineScope,
                )
            }
        },
        paneExpansionState =
            rememberPaneExpansionState(
                keyProvider = scaffoldNavigator.scaffoldValue,
                anchors = PaneExpansionAnchors,
                initialAnchoredIndex = 1,
            ),
        paneExpansionDragHandle = { state -> PaneExpansionDragHandleSample(state) },
    )
}

SupportingPaneScaffoldSampleWithExtraPaneLevitatedAsBottomSheet

/**
 * This sample shows how to create a [SupportingPaneScaffold] that shows the extra pane as a bottom
 * sheet when it's a single-pane layout and the extra pane is the current destination.
 *
 * @see levitateAsDialogSample for more usage samples of [AdaptStrategy.Levitate].
 */
@OptIn(ExperimentalMaterial3AdaptiveApi::class, ExperimentalMaterial3Api::class)
@Preview
@Composable
fun SupportingPaneScaffoldSampleWithExtraPaneLevitatedAsBottomSheet() {
    val coroutineScope = rememberCoroutineScope()
    val scaffoldNavigator = levitateAsBottomSheetSample<NavItemData>()
    val extraItems = listOf("Extra content")
    val selectedItem = NavItemData(index = 0, showExtra = true)
    SupportingPaneScaffold(
        directive = scaffoldNavigator.scaffoldDirective,
        scaffoldState = scaffoldNavigator.scaffoldState,
        mainPane = {
            AnimatedPane {
                MainPaneContent(
                    scaffoldNavigator = scaffoldNavigator,
                    hasExtraPane = true,
                    coroutineScope = coroutineScope,
                )
            }
        },
        supportingPane = {
            AnimatedPane(modifier = Modifier.preferredWidth(200.dp)) { SupportingPaneContent() }
        },
        extraPane = {
            AnimatedPane(
                modifier =
                    Modifier.preferredWidth(1f)
                        .preferredHeight(0.5f)
                        .background(MaterialTheme.colorScheme.surface),
                dragToResizeHandle = { BottomSheetDefaults.DragHandle() },
            ) {
                ExtraPaneContent(
                    extraItems = extraItems,
                    selectedItem = selectedItem,
                    scaffoldNavigator = scaffoldNavigator,
                    coroutineScope = coroutineScope,
                )
            }
        },
        paneExpansionState =
            rememberPaneExpansionState(
                keyProvider = scaffoldNavigator.scaffoldValue,
                anchors = PaneExpansionAnchors,
            ),
        paneExpansionDragHandle = { state -> PaneExpansionDragHandleSample(state) },
    )
}

levitateAsBottomSheetSample

/**
 * This sample shows how to create a [ThreePaneScaffoldNavigator] that will show the extra pane as a
 * bottom sheet in a single pane layout when the extra pane is the current destination.
 *
 * The key parts of this sample are:
 * 1. [rememberSupportingPaneScaffoldNavigator] with a custom
 *    [androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies] that provides
 *    [AdaptStrategy.Levitate] with [Alignment.BottomCenter] for the extra pane.
 * 2. The use of [androidx.compose.material3.adaptive.layout.AdaptStrategy.Levitate] with a
 *    remembered [DragToResizeState] with [DockedEdge.Bottom] so that the levitated extra pane can
 *    be resized by dragging and docked to the bottom of the layout.
 */
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Preview
@Composable
fun <T> levitateAsBottomSheetSample(): ThreePaneScaffoldNavigator<T> {
    val scaffoldDirective = calculatePaneScaffoldDirective(currentWindowAdaptiveInfoV2())
    val dragToResizeState = rememberDragToResizeState(dockedEdge = DockedEdge.Bottom)
    var navigator: ThreePaneScaffoldNavigator<T>? = null
    navigator =
        rememberSupportingPaneScaffoldNavigator<T>(
            scaffoldDirective = scaffoldDirective,
            adaptStrategies =
                SupportingPaneScaffoldDefaults.adaptStrategies(
                    extraPaneAdaptStrategy =
                        AdaptStrategy.Levitate(
                                alignment = Alignment.BottomCenter,
                                dragToResizeState = dragToResizeState,
                            )
                            .onlyIfSinglePane(scaffoldDirective)
                ),
        )
    return navigator
}

levitateAsDialogSample

/**
 * This sample shows how to create a [ThreePaneScaffoldNavigator] that will show the extra pane as a
 * modal dialog when the extra pane is the current destination. The dialog will be centered in the
 * scaffold, with a scrim that clicking on it will dismiss the dialog.
 */
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Preview
@Composable
fun <T> levitateAsDialogSample(): ThreePaneScaffoldNavigator<T> {
    val coroutineScope = rememberCoroutineScope()
    val scaffoldDirective = calculatePaneScaffoldDirective(currentWindowAdaptiveInfoV2())
    var navigator: ThreePaneScaffoldNavigator<T>? = null
    val onClick: () -> Unit = { coroutineScope.launch { navigator?.navigateBack() } }
    navigator =
        rememberListDetailPaneScaffoldNavigator<T>(
            scaffoldDirective = scaffoldDirective,
            adaptStrategies =
                SupportingPaneScaffoldDefaults.adaptStrategies(
                    extraPaneAdaptStrategy =
                        AdaptStrategy.Levitate(
                                alignment = Alignment.Center,
                                scrim = {
                                    LevitatedPaneScrim(
                                        Modifier.semantics {
                                            contentDescription = "Scrim"
                                            this.onClick("Dismiss the extra pane") {
                                                onClick()
                                                true
                                            }
                                        },
                                        onClick = onClick,
                                    )
                                },
                            )
                            .onlyIfSinglePane(scaffoldDirective)
                ),
        )
    return navigator
}