androidx.compose.material3.adaptive.navigation

Interfaces

ThreePaneScaffoldNavigator

The common interface of the default navigation implementations for different three-pane scaffolds.

Cmn

Classes

BackNavigationBehavior

A class to control how back navigation should behave in a ThreePaneScaffoldNavigator.

Cmn

Top-level functions summary

Unit
@ExperimentalMaterial3AdaptiveApi
@Composable
<T : Any?> NavigableListDetailPaneScaffold(
    navigator: ThreePaneScaffoldNavigator<T>,
    listPane: @Composable ThreePaneScaffoldPaneScope.() -> Unit,
    detailPane: @Composable ThreePaneScaffoldPaneScope.() -> Unit,
    modifier: Modifier,
    extraPane: (@Composable ThreePaneScaffoldPaneScope.() -> Unit)?,
    defaultBackBehavior: BackNavigationBehavior,
    paneExpansionDragHandle: (@Composable ThreePaneScaffoldScope.(PaneExpansionState) -> Unit)?,
    paneExpansionState: PaneExpansionState?
)

A version of ListDetailPaneScaffold that supports navigation and predictive back handling out of the box, controlled by ThreePaneScaffoldNavigator.

android
Unit
@ExperimentalMaterial3AdaptiveApi
@Composable
<T : Any?> NavigableSupportingPaneScaffold(
    navigator: ThreePaneScaffoldNavigator<T>,
    mainPane: @Composable ThreePaneScaffoldPaneScope.() -> Unit,
    supportingPane: @Composable ThreePaneScaffoldPaneScope.() -> Unit,
    modifier: Modifier,
    extraPane: (@Composable ThreePaneScaffoldPaneScope.() -> Unit)?,
    defaultBackBehavior: BackNavigationBehavior,
    paneExpansionDragHandle: (@Composable ThreePaneScaffoldScope.(PaneExpansionState) -> Unit)?,
    paneExpansionState: PaneExpansionState?
)

A version of SupportingPaneScaffold that supports navigation and predictive back handling out of the box, controlled by ThreePaneScaffoldNavigator.

android
Unit

An effect to add predictive back handling to a three pane scaffold.

android
ThreePaneScaffoldNavigator<Any>
@ExperimentalMaterial3AdaptiveApi
@Composable
rememberListDetailPaneScaffoldNavigator(
    scaffoldDirective: PaneScaffoldDirective,
    adaptStrategies: ThreePaneScaffoldAdaptStrategies,
    isDestinationHistoryAware: Boolean
)

Returns a remembered default implementation of ThreePaneScaffoldNavigator for ListDetailPaneScaffold, which will be updated automatically when the input values change.

Cmn
ThreePaneScaffoldNavigator<T>
@ExperimentalMaterial3AdaptiveApi
@Composable
<T : Any?> rememberListDetailPaneScaffoldNavigator(
    scaffoldDirective: PaneScaffoldDirective,
    adaptStrategies: ThreePaneScaffoldAdaptStrategies,
    isDestinationHistoryAware: Boolean,
    initialDestinationHistory: List<ThreePaneScaffoldDestinationItem<T>>
)

Returns a remembered default implementation of ThreePaneScaffoldNavigator for ListDetailPaneScaffold, which will be updated automatically when the input values change.

Cmn
ThreePaneScaffoldNavigator<Any>
@ExperimentalMaterial3AdaptiveApi
@Composable
rememberSupportingPaneScaffoldNavigator(
    scaffoldDirective: PaneScaffoldDirective,
    adaptStrategies: ThreePaneScaffoldAdaptStrategies,
    isDestinationHistoryAware: Boolean
)

Returns a remembered default implementation of ThreePaneScaffoldNavigator for SupportingPaneScaffold, which will be updated automatically when the input values change.

Cmn
ThreePaneScaffoldNavigator<T>
@ExperimentalMaterial3AdaptiveApi
@Composable
<T : Any?> rememberSupportingPaneScaffoldNavigator(
    scaffoldDirective: PaneScaffoldDirective,
    adaptStrategies: ThreePaneScaffoldAdaptStrategies,
    isDestinationHistoryAware: Boolean,
    initialDestinationHistory: List<ThreePaneScaffoldDestinationItem<T>>
)

Returns a remembered default implementation of ThreePaneScaffoldNavigator for SupportingPaneScaffold, which will be updated automatically when the input values change.

Cmn

Top-level functions

@ExperimentalMaterial3AdaptiveApi
@Composable
fun <T : Any?> NavigableListDetailPaneScaffold(
    navigator: ThreePaneScaffoldNavigator<T>,
    listPane: @Composable ThreePaneScaffoldPaneScope.() -> Unit,
    detailPane: @Composable ThreePaneScaffoldPaneScope.() -> Unit,
    modifier: Modifier = Modifier,
    extraPane: (@Composable ThreePaneScaffoldPaneScope.() -> Unit)? = null,
    defaultBackBehavior: BackNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange,
    paneExpansionDragHandle: (@Composable ThreePaneScaffoldScope.(PaneExpansionState) -> Unit)? = null,
    paneExpansionState: PaneExpansionState? = null
): Unit

A version of ListDetailPaneScaffold that supports navigation and predictive back handling out of the box, controlled by ThreePaneScaffoldNavigator.

Example usage, including integration with the Compose Navigation library:

import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.adaptive.layout.AnimatedPane
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold
import androidx.compose.material3.adaptive.navigation.BackNavigationBehavior
import androidx.compose.material3.adaptive.navigation.NavigableListDetailPaneScaffold
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController

val welcomeRoute = "welcome"
val listDetailRoute = "listdetail"

// `navController` handles navigation outside the ListDetailPaneScaffold,
// and `scaffoldNavigator` handles navigation within it. The "content" of
// the scaffold uses a custom type which tracks the index of the selected item,
// which is passed as a type argument to `rememberListDetailPaneScaffoldNavigator`.
val navController = rememberNavController()
val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator<NavItemData>()

// Back behavior can be customized based on the needs of the app.
var backBehaviorIndex by rememberSaveable { mutableStateOf(0) }
val backBehaviors =
    listOf(
        BackNavigationBehavior.PopUntilScaffoldValueChange,
        BackNavigationBehavior.PopUntilCurrentDestinationChange,
        BackNavigationBehavior.PopUntilContentChange,
        BackNavigationBehavior.PopLatest,
    )
val backBehavior = backBehaviors[backBehaviorIndex]

val items = listOf("Item 1", "Item 2", "Item 3")
val extraItems = listOf("Extra 1", "Extra 2", "Extra 3")

NavHost(
    navController = navController,
    startDestination = welcomeRoute,
    enterTransition = { slideInHorizontally(initialOffsetX = { it }) },
    exitTransition = { slideOutHorizontally(targetOffsetX = { -it }) },
    popEnterTransition = { slideInHorizontally(initialOffsetX = { -it }) },
    popExitTransition = { slideOutHorizontally(targetOffsetX = { it }) },
) {
    composable(welcomeRoute) {
        Scaffold(Modifier.fillMaxSize()) { paddingValues ->
            Column(
                modifier =
                    Modifier.verticalScroll(rememberScrollState())
                        .padding(paddingValues)
                        .padding(24.dp)
                        .fillMaxSize(),
                verticalArrangement = Arrangement.spacedBy(16.dp),
            ) {
                Text(
                    text = "How should the scaffold handle back navigation?",
                    style = MaterialTheme.typography.headlineMedium,
                )
                RadioButtonRow(
                    selected = backBehaviorIndex == 0,
                    onClick = { backBehaviorIndex = 0 },
                    text =
                        "PopUntilScaffoldValueChange - Back navigation forces a change in " +
                            "which pane(s) is/are shown."
                )
                RadioButtonRow(
                    selected = backBehaviorIndex == 1,
                    onClick = { backBehaviorIndex = 1 },
                    text =
                        "PopUntilCurrentDestinationChange - Back navigation forces a " +
                            "change in which pane is currently considered \"active\"."
                )
                RadioButtonRow(
                    selected = backBehaviorIndex == 2,
                    onClick = { backBehaviorIndex = 2 },
                    text =
                        "PopUntilContentChange - Back navigation forces a change in the " +
                            "content of any pane or which pane(s) is/are shown.\nNote: this " +
                            "may result in unintuitive behavior if the device size changes " +
                            "in the middle of the navigation."
                )
                RadioButtonRow(
                    selected = backBehaviorIndex == 3,
                    onClick = { backBehaviorIndex = 3 },
                    text =
                        "PopLatest - No special back handling.\nNote: this may result in " +
                            "unintuitive behavior if the device size changes in the middle " +
                            "of the navigation."
                )
                Button(
                    onClick = { navController.navigate(listDetailRoute) },
                ) {
                    Text("Next")
                }
            }
        }
    }
    composable(listDetailRoute) {
        val selectedItem = scaffoldNavigator.currentDestination?.contentKey
        NavigableListDetailPaneScaffold(
            navigator = scaffoldNavigator,
            defaultBackBehavior = backBehavior,
            listPane = {
                AnimatedPane(Modifier.preferredWidth(200.dp)) {
                    ListPaneContent(
                        items = items,
                        selectedItem = selectedItem,
                        scaffoldNavigator = scaffoldNavigator,
                    )
                }
            },
            detailPane = {
                AnimatedPane {
                    DetailPaneContent(
                        items = items,
                        selectedItem = selectedItem,
                        scaffoldNavigator = scaffoldNavigator,
                        hasExtraPane = true,
                        backBehavior = backBehavior,
                    )
                }
            },
            extraPane = {
                AnimatedPane {
                    ExtraPaneContent(
                        extraItems = extraItems,
                        selectedItem = selectedItem,
                        scaffoldNavigator = scaffoldNavigator,
                        backBehavior = backBehavior,
                    )
                }
            },
        )
    }
}
Parameters
navigator: ThreePaneScaffoldNavigator<T>

The navigator instance to navigate through the scaffold.

listPane: @Composable ThreePaneScaffoldPaneScope.() -> Unit

the list pane of the scaffold, which is supposed to hold a list of item summaries that can be selected from, for example, the inbox mail list of a mail app. See ListDetailPaneScaffoldRole.List. Note that we suggest you to use AnimatedPane as the root layout of panes, which supports default pane behaviors like enter/exit transitions.

detailPane: @Composable ThreePaneScaffoldPaneScope.() -> Unit

the detail pane of the scaffold, which is supposed to hold the detailed info of a selected item, for example, the mail content currently being viewed. See ListDetailPaneScaffoldRole.Detail. Note that we suggest you to use AnimatedPane as the root layout of panes, which supports default pane behaviors like enter/exit transitions.

modifier: Modifier = Modifier

Modifier of the scaffold layout.

extraPane: (@Composable ThreePaneScaffoldPaneScope.() -> Unit)? = null

the extra pane of the scaffold, which is supposed to hold any supplementary info besides the list and the detail panes, for example, a task list or a mini-calendar view of a mail app. See ListDetailPaneScaffoldRole.Extra. Note that we suggest you to use AnimatedPane as the root layout of panes, which supports default pane behaviors like enter/exit transitions.

defaultBackBehavior: BackNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange

the default back navigation behavior when the system back event happens. See BackNavigationBehavior for the use cases of each behavior.

paneExpansionDragHandle: (@Composable ThreePaneScaffoldScope.(PaneExpansionState) -> Unit)? = null

the pane expansion drag handle to allow users to drag to change pane expansion state, null by default.

paneExpansionState: PaneExpansionState? = null

the state object of pane expansion; when no value is provided but paneExpansionDragHandle is not null, a default implementation will be created for the drag handle to use.

@ExperimentalMaterial3AdaptiveApi
@Composable
fun <T : Any?> NavigableSupportingPaneScaffold(
    navigator: ThreePaneScaffoldNavigator<T>,
    mainPane: @Composable ThreePaneScaffoldPaneScope.() -> Unit,
    supportingPane: @Composable ThreePaneScaffoldPaneScope.() -> Unit,
    modifier: Modifier = Modifier,
    extraPane: (@Composable ThreePaneScaffoldPaneScope.() -> Unit)? = null,
    defaultBackBehavior: BackNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange,
    paneExpansionDragHandle: (@Composable ThreePaneScaffoldScope.(PaneExpansionState) -> Unit)? = null,
    paneExpansionState: PaneExpansionState? = null
): Unit

A version of SupportingPaneScaffold that supports navigation and predictive back handling out of the box, controlled by ThreePaneScaffoldNavigator.

Parameters
navigator: ThreePaneScaffoldNavigator<T>

The navigator instance to navigate through the scaffold.

mainPane: @Composable ThreePaneScaffoldPaneScope.() -> Unit

the main pane of the scaffold, which is supposed to hold the major content of an app, for example, the editing screen of a doc app. See SupportingPaneScaffoldRole.Main. Note that we suggest you to use AnimatedPane as the root layout of panes, which supports default pane behaviors like enter/exit transitions.

supportingPane: @Composable ThreePaneScaffoldPaneScope.() -> Unit

the supporting pane of the scaffold, which is supposed to hold the support content of an app, for example, the comment list of a doc app. See SupportingPaneScaffoldRole.Supporting. Note that we suggest you to use AnimatedPane as the root layout of panes, which supports default pane behaviors like enter/exit transitions.

modifier: Modifier = Modifier

Modifier of the scaffold layout.

extraPane: (@Composable ThreePaneScaffoldPaneScope.() -> Unit)? = null

the extra pane of the scaffold, which is supposed to hold any additional content besides the main and the supporting panes, for example, a styling panel in a doc app. See SupportingPaneScaffoldRole.Extra. Note that we suggest you to use AnimatedPane as the root layout of panes, which supports default pane behaviors like enter/exit transitions.

defaultBackBehavior: BackNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange

the default back navigation behavior when the system back event happens. See BackNavigationBehavior for the use cases of each behavior.

paneExpansionDragHandle: (@Composable ThreePaneScaffoldScope.(PaneExpansionState) -> Unit)? = null

the pane expansion drag handle to allow users to drag to change pane expansion state, null by default.

paneExpansionState: PaneExpansionState? = null

the state object of pane expansion; when no value is provided but paneExpansionDragHandle is not null, a default implementation will be created for the drag handle to use.

ThreePaneScaffoldPredictiveBackHandler

@ExperimentalMaterial3AdaptiveApi
@Composable
fun <T : Any?> ThreePaneScaffoldPredictiveBackHandler(
    navigator: ThreePaneScaffoldNavigator<T>,
    backBehavior: BackNavigationBehavior
): Unit

An effect to add predictive back handling to a three pane scaffold.

NavigableListDetailPaneScaffold and NavigableSupportingPaneScaffold apply this effect automatically. If instead you are using ListDetailPaneScaffold or SupportingPaneScaffold, use the overloads that accept a ThreePaneScaffoldState and pass navigator.scaffoldState to the scaffold after adding this effect to your composition.

A predictive back gesture will cause the navigator to seekBack to the previous scaffold value. The progress can be read from the progressFraction of the navigator's scaffold state. It will range from 0 (representing the start of the predictive back gesture) to some fraction less than 1 (representing a "peek" or "preview" of the previous scaffold value). If the gesture is committed, back navigation is performed. If the gesture is cancelled, the navigator's scaffold state is reset.

Parameters
navigator: ThreePaneScaffoldNavigator<T>

The navigator instance to navigate through the scaffold.

backBehavior: BackNavigationBehavior

The back navigation behavior when the system back event happens. See BackNavigationBehavior.

rememberListDetailPaneScaffoldNavigator

@ExperimentalMaterial3AdaptiveApi
@Composable
fun rememberListDetailPaneScaffoldNavigator(
    scaffoldDirective: PaneScaffoldDirective = calculatePaneScaffoldDirective(currentWindowAdaptiveInfo()),
    adaptStrategies: ThreePaneScaffoldAdaptStrategies = ListDetailPaneScaffoldDefaults.adaptStrategies(),
    isDestinationHistoryAware: Boolean = true
): ThreePaneScaffoldNavigator<Any>

Returns a remembered default implementation of ThreePaneScaffoldNavigator for ListDetailPaneScaffold, which will be updated automatically when the input values change. The default navigator is supposed to be used independently from any navigation frameworks and handles the navigation purely inside the ListDetailPaneScaffold.

Parameters
scaffoldDirective: PaneScaffoldDirective = calculatePaneScaffoldDirective(currentWindowAdaptiveInfo())

the current layout directives to follow. The default value will be calculated with calculatePaneScaffoldDirective using WindowAdaptiveInfo retrieved from the current context.

adaptStrategies: ThreePaneScaffoldAdaptStrategies = ListDetailPaneScaffoldDefaults.adaptStrategies()

adaptation strategies of each pane.

isDestinationHistoryAware: Boolean = true

true if the scaffold value calculation should be aware of the full destination history, instead of just the current destination. See calculateThreePaneScaffoldValue for more relevant details.

rememberListDetailPaneScaffoldNavigator

@ExperimentalMaterial3AdaptiveApi
@Composable
fun <T : Any?> rememberListDetailPaneScaffoldNavigator(
    scaffoldDirective: PaneScaffoldDirective = calculatePaneScaffoldDirective(currentWindowAdaptiveInfo()),
    adaptStrategies: ThreePaneScaffoldAdaptStrategies = ListDetailPaneScaffoldDefaults.adaptStrategies(),
    isDestinationHistoryAware: Boolean = true,
    initialDestinationHistory: List<ThreePaneScaffoldDestinationItem<T>> = DefaultListDetailPaneHistory
): ThreePaneScaffoldNavigator<T>

Returns a remembered default implementation of ThreePaneScaffoldNavigator for ListDetailPaneScaffold, which will be updated automatically when the input values change. The default navigator is supposed to be used independently from any navigation frameworks and handles the navigation purely inside the ListDetailPaneScaffold.

Parameters
<T : Any?>

the type representing the content key/id for a navigation destination. This type must be storable in a Bundle. Used to customize navigation behavior (for example, BackNavigationBehavior). If this customization is unneeded, you can pass Any.

scaffoldDirective: PaneScaffoldDirective = calculatePaneScaffoldDirective(currentWindowAdaptiveInfo())

the current layout directives to follow. The default value will be calculated with calculatePaneScaffoldDirective using WindowAdaptiveInfo retrieved from the current context.

adaptStrategies: ThreePaneScaffoldAdaptStrategies = ListDetailPaneScaffoldDefaults.adaptStrategies()

adaptation strategies of each pane.

isDestinationHistoryAware: Boolean = true

true if the scaffold value calculation should be aware of the full destination history, instead of just the current destination. See calculateThreePaneScaffoldValue for more relevant details.

initialDestinationHistory: List<ThreePaneScaffoldDestinationItem<T>> = DefaultListDetailPaneHistory

the initial pane destination history of the scaffold, by default it will be just the list pane.

rememberSupportingPaneScaffoldNavigator

@ExperimentalMaterial3AdaptiveApi
@Composable
fun rememberSupportingPaneScaffoldNavigator(
    scaffoldDirective: PaneScaffoldDirective = calculatePaneScaffoldDirective(currentWindowAdaptiveInfo()),
    adaptStrategies: ThreePaneScaffoldAdaptStrategies = SupportingPaneScaffoldDefaults.adaptStrategies(),
    isDestinationHistoryAware: Boolean = true
): ThreePaneScaffoldNavigator<Any>

Returns a remembered default implementation of ThreePaneScaffoldNavigator for SupportingPaneScaffold, which will be updated automatically when the input values change. The default navigator is supposed to be used independently from any navigation frameworks and handles the navigation purely inside the SupportingPaneScaffold.

Parameters
scaffoldDirective: PaneScaffoldDirective = calculatePaneScaffoldDirective(currentWindowAdaptiveInfo())

the current layout directives to follow. The default value will be calculated with calculatePaneScaffoldDirective using WindowAdaptiveInfo retrieved from the current context.

adaptStrategies: ThreePaneScaffoldAdaptStrategies = SupportingPaneScaffoldDefaults.adaptStrategies()

adaptation strategies of each pane.

isDestinationHistoryAware: Boolean = true

true if the scaffold value calculation should be aware of the full destination history, instead of just the current destination. See calculateThreePaneScaffoldValue for more relevant details.

rememberSupportingPaneScaffoldNavigator

@ExperimentalMaterial3AdaptiveApi
@Composable
fun <T : Any?> rememberSupportingPaneScaffoldNavigator(
    scaffoldDirective: PaneScaffoldDirective = calculatePaneScaffoldDirective(currentWindowAdaptiveInfo()),
    adaptStrategies: ThreePaneScaffoldAdaptStrategies = SupportingPaneScaffoldDefaults.adaptStrategies(),
    isDestinationHistoryAware: Boolean = true,
    initialDestinationHistory: List<ThreePaneScaffoldDestinationItem<T>> = DefaultSupportingPaneHistory
): ThreePaneScaffoldNavigator<T>

Returns a remembered default implementation of ThreePaneScaffoldNavigator for SupportingPaneScaffold, which will be updated automatically when the input values change. The default navigator is supposed to be used independently from any navigation frameworks and handles the navigation purely inside the SupportingPaneScaffold.

Parameters
<T : Any?>

the type representing the content key/id for a navigation destination. This type must be storable in a Bundle. Used to customize navigation behavior (for example, BackNavigationBehavior). If this customization is unneeded, you can pass Any.

scaffoldDirective: PaneScaffoldDirective = calculatePaneScaffoldDirective(currentWindowAdaptiveInfo())

the current layout directives to follow. The default value will be calculated with calculatePaneScaffoldDirective using WindowAdaptiveInfo retrieved from the current context.

adaptStrategies: ThreePaneScaffoldAdaptStrategies = SupportingPaneScaffoldDefaults.adaptStrategies()

adaptation strategies of each pane.

isDestinationHistoryAware: Boolean = true

true if the scaffold value calculation should be aware of the full destination history, instead of just the current destination. See calculateThreePaneScaffoldValue for more relevant details.

initialDestinationHistory: List<ThreePaneScaffoldDestinationItem<T>> = DefaultSupportingPaneHistory

the initial destination history of the scaffold, by default it will be just the main pane.