androidx.navigation3.ui


Interfaces

OverlayScene

A specific scene to render 1 or more NavEntry instances as an overlay.

Cmn
Scene

A specific scene to render 1 or more NavEntrys.

Cmn
SceneStrategy

A strategy that tries to calculate a Scene given a list of NavEntry.

Cmn

Classes

DialogSceneStrategy

A SceneStrategy that displays entries that have added dialog to their NavEntry.metadata within a Dialog instance.

Cmn
SinglePaneSceneStrategy

A SceneStrategy that always creates a 1-entry Scene simply displaying the last entry in the list.

Cmn

Objects

NavDisplay

Object that indicates the features that can be handled by the NavDisplay

Cmn

Top-level functions summary

Unit
@Composable
<T : Any> NavDisplay(
    backStack: List<T>,
    modifier: Modifier,
    contentAlignment: Alignment,
    onBack: (Int) -> Unit,
    entryDecorators: List<NavEntryDecorator<*>>,
    sceneStrategy: SceneStrategy<T>,
    sizeTransform: SizeTransform?,
    transitionSpec: AnimatedContentTransitionScope<*>.() -> ContentTransform,
    popTransitionSpec: AnimatedContentTransitionScope<*>.() -> ContentTransform,
    predictivePopTransitionSpec: AnimatedContentTransitionScope<*>.() -> ContentTransform,
    entryProvider: (key) -> NavEntry<T>
)

A nav display that renders and animates between different Scenes, each of which can render one or more NavEntrys.

Cmn
NavEntryDecorator<Any>

A NavEntryDecorator that wraps each entry in a movableContentOf to allow nav displays to arbitrarily place entries in different places in the composable call hierarchy and ensures that the same entry content is not composed multiple times in different places of the hierarchy.

Cmn
NavEntryDecorator<Any>

Returns a SceneSetupNavEntryDecorator that is remembered across recompositions.

Cmn

Top-level properties summary

ProvidableCompositionLocal<Set<Any>>

The entry keys to render in the current Scene, in the sense of the target of the animation for an AnimatedContent that is transitioning between different scenes.

Cmn
ProvidableCompositionLocal<AnimatedContentScope>

Local provider of AnimatedContentScope to androidx.navigation3.runtime.NavEntry.content.

Cmn

Top-level functions

@Composable
fun <T : Any> NavDisplay(
    backStack: List<T>,
    modifier: Modifier = Modifier,
    contentAlignment: Alignment = Alignment.TopStart,
    onBack: (Int) -> Unit = { if (backStack is MutableList<T>) { repeat(it) { backStack.removeAt(backStack.lastIndex) } } },
    entryDecorators: List<NavEntryDecorator<*>> = listOf(rememberSceneSetupNavEntryDecorator(), rememberSavedStateNavEntryDecorator()),
    sceneStrategy: SceneStrategy<T> = SinglePaneSceneStrategy(),
    sizeTransform: SizeTransform? = null,
    transitionSpec: AnimatedContentTransitionScope<*>.() -> ContentTransform = { ContentTransform( fadeIn(animationSpec = tween(DEFAULT_TRANSITION_DURATION_MILLISECOND)), fadeOut(animationSpec = tween(DEFAULT_TRANSITION_DURATION_MILLISECOND)), ) },
    popTransitionSpec: AnimatedContentTransitionScope<*>.() -> ContentTransform = { ContentTransform( fadeIn(animationSpec = tween(DEFAULT_TRANSITION_DURATION_MILLISECOND)), fadeOut(animationSpec = tween(DEFAULT_TRANSITION_DURATION_MILLISECOND)), ) },
    predictivePopTransitionSpec: AnimatedContentTransitionScope<*>.() -> ContentTransform = NavDisplay.defaultPredictivePopTransitionSpec,
    entryProvider: (key) -> NavEntry<T>
): Unit

A nav display that renders and animates between different Scenes, each of which can render one or more NavEntrys.

The Scenes are calculated with the given SceneStrategy, which may be an assembled delegated chain of SceneStrategys. If no Scene is calculated, the fallback will be to a SinglePaneSceneStrategy.

It is allowable for different Scenes to render the same NavEntrys, perhaps on some conditions as determined by the sceneStrategy based on window size, form factor, other arbitrary logic.

If this happens, and these Scenes are rendered at the same time due to animation or predictive back, then the content for the NavEntry will only be rendered in the most recent Scene that is the target for being the current scene as determined by sceneStrategy. This enforces a unique invocation of each NavEntry, even if it is displayable by two different Scenes.

import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import androidx.compose.material3.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator
import androidx.navigation3.runtime.NavEntry
import androidx.navigation3.runtime.NavEntryDecorator
import androidx.navigation3.runtime.entry
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.runtime.rememberSavedStateNavEntryDecorator
import androidx.navigation3.runtime.samples.Dashboard
import androidx.navigation3.runtime.samples.DialogBase
import androidx.navigation3.runtime.samples.DialogContent
import androidx.navigation3.runtime.samples.Profile
import androidx.navigation3.runtime.samples.ProfileViewModel
import androidx.navigation3.runtime.samples.Scrollable
import androidx.navigation3.ui.NavDisplay
import androidx.navigation3.ui.Scene
import androidx.navigation3.ui.rememberSceneSetupNavEntryDecorator

val backStack = rememberNavBackStack(Profile)
val showDialog = remember { mutableStateOf(false) }
NavDisplay(
    backStack = backStack,
    entryDecorators =
        listOf(
            rememberSceneSetupNavEntryDecorator(),
            rememberSavedStateNavEntryDecorator(),
            rememberViewModelStoreNavEntryDecorator(),
        ),
    onBack = { backStack.removeAt(backStack.lastIndex) },
    entryProvider =
        entryProvider({ NavEntry(it) { Text(text = "Invalid Key") } }) {
            entry<Profile> {
                val viewModel = viewModel<ProfileViewModel>()
                Profile(viewModel, { backStack.add(it) }) {
                    backStack.removeAt(backStack.lastIndex)
                }
            }
            entry<Scrollable> {
                Scrollable({ backStack.add(it) }) { backStack.removeAt(backStack.lastIndex) }
            }
            entry<DialogBase> {
                DialogBase(onClick = { showDialog.value = true }) {
                    backStack.removeAt(backStack.lastIndex)
                }
            }
            entry<Dashboard>(
                metadata =
                    NavDisplay.predictivePopTransitionSpec {
                        slideInHorizontally(tween(700)) { it / 2 } togetherWith
                            slideOutHorizontally(tween(700)) { -it / 2 }
                    }
            ) { dashboardArgs ->
                val userId = dashboardArgs.userId
                Dashboard(userId, onBack = { backStack.removeAt(backStack.lastIndex) })
            }
        },
)
if (showDialog.value) {
    DialogContent(onDismissRequest = { showDialog.value = false })
}
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.animation.SharedTransitionScope
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.navigation3.runtime.NavEntry
import androidx.navigation3.runtime.NavEntryDecorator
import androidx.navigation3.runtime.entry
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.navEntryDecorator
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.runtime.rememberSavedStateNavEntryDecorator
import androidx.navigation3.ui.LocalNavAnimatedContentScope
import androidx.navigation3.ui.NavDisplay
import androidx.navigation3.ui.Scene
import androidx.navigation3.ui.rememberSceneSetupNavEntryDecorator

/** The [SharedTransitionScope] of the [NavDisplay]. */
val localNavSharedTransitionScope: ProvidableCompositionLocal<SharedTransitionScope> =
    compositionLocalOf {
        throw IllegalStateException(
            "Unexpected access to LocalNavSharedTransitionScope. You must provide a " +
                "SharedTransitionScope from a call to SharedTransitionLayout() or " +
                "SharedTransitionScope()"
        )
    }

/**
 * A [NavEntryDecorator] that wraps each entry in a shared element that is controlled by the
 * [Scene].
 */
val sharedEntryInSceneNavEntryDecorator = navEntryDecorator { entry ->
    with(localNavSharedTransitionScope.current) {
        Box(
            Modifier.sharedElement(
                rememberSharedContentState(entry.key),
                animatedVisibilityScope = LocalNavAnimatedContentScope.current,
            )
        ) {
            entry.content(entry.key)
        }
    }
}

val backStack = rememberNavBackStack(CatList)
SharedTransitionLayout {
    CompositionLocalProvider(localNavSharedTransitionScope provides this) {
        NavDisplay(
            backStack = backStack,
            onBack = { backStack.removeAt(backStack.lastIndex) },
            entryDecorators =
                listOf(
                    sharedEntryInSceneNavEntryDecorator,
                    rememberSceneSetupNavEntryDecorator(),
                    rememberSavedStateNavEntryDecorator(),
                ),
            entryProvider =
                entryProvider {
                    entry<CatList> {
                        CatList(this@SharedTransitionLayout) { cat ->
                            backStack.add(CatDetail(cat))
                        }
                    }
                    entry<CatDetail> { args ->
                        CatDetail(args.cat, this@SharedTransitionLayout) {
                            backStack.removeAt(backStack.lastIndex)
                        }
                    }
                },
        )
    }
}
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.runtime.remember
import androidx.navigation3.runtime.entry
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.ui.NavDisplay

val backStack = rememberNavBackStack(CatList)
SharedTransitionLayout {
    NavDisplay(
        backStack = backStack,
        onBack = { backStack.removeAt(backStack.lastIndex) },
        entryProvider =
            entryProvider {
                entry<CatList> {
                    CatList(this@SharedTransitionLayout) { cat ->
                        backStack.add(CatDetail(cat))
                    }
                }
                entry<CatDetail> { args ->
                    CatDetail(args.cat, this@SharedTransitionLayout) {
                        backStack.removeAt(backStack.lastIndex)
                    }
                }
            },
    )
}
Parameters
backStack: List<T>

the collection of keys that represents the state that needs to be handled

modifier: Modifier = Modifier

the modifier to be applied to the layout.

contentAlignment: Alignment = Alignment.TopStart

The Alignment of the AnimatedContent

onBack: (Int) -> Unit = { if (backStack is MutableList<T>) { repeat(it) { backStack.removeAt(backStack.lastIndex) } } }

a callback for handling system back press. The passed Int refers to the number of entries to pop from the end of the backstack, as calculated by the sceneStrategy.

entryDecorators: List<NavEntryDecorator<*>> = listOf(rememberSceneSetupNavEntryDecorator(), rememberSavedStateNavEntryDecorator())

list of NavEntryDecorator to add information to the entry content

sceneStrategy: SceneStrategy<T> = SinglePaneSceneStrategy()

the SceneStrategy to determine which scene to render a list of entries.

sizeTransform: SizeTransform? = null

the SizeTransform for the AnimatedContent.

transitionSpec: AnimatedContentTransitionScope<*>.() -> ContentTransform = { ContentTransform( fadeIn(animationSpec = tween(DEFAULT_TRANSITION_DURATION_MILLISECOND)), fadeOut(animationSpec = tween(DEFAULT_TRANSITION_DURATION_MILLISECOND)), ) }

Default ContentTransform when navigating to NavEntrys.

popTransitionSpec: AnimatedContentTransitionScope<*>.() -> ContentTransform = { ContentTransform( fadeIn(animationSpec = tween(DEFAULT_TRANSITION_DURATION_MILLISECOND)), fadeOut(animationSpec = tween(DEFAULT_TRANSITION_DURATION_MILLISECOND)), ) }

Default ContentTransform when popping NavEntrys.

predictivePopTransitionSpec: AnimatedContentTransitionScope<*>.() -> ContentTransform = NavDisplay.defaultPredictivePopTransitionSpec

Default ContentTransform when popping with predictive back NavEntrys.

entryProvider: (key) -> NavEntry<T>

lambda used to construct each possible NavEntry

SceneSetupNavEntryDecorator

fun SceneSetupNavEntryDecorator(): NavEntryDecorator<Any>

A NavEntryDecorator that wraps each entry in a movableContentOf to allow nav displays to arbitrarily place entries in different places in the composable call hierarchy and ensures that the same entry content is not composed multiple times in different places of the hierarchy.

This should likely be the first NavEntryDecorator to ensure that other NavEntryDecorator calls that are stateful are moved properly inside the movableContentOf.

rememberSceneSetupNavEntryDecorator

@Composable
fun rememberSceneSetupNavEntryDecorator(): NavEntryDecorator<Any>

Returns a SceneSetupNavEntryDecorator that is remembered across recompositions.

Top-level properties

LocalEntriesToRenderInCurrentScene

val LocalEntriesToRenderInCurrentSceneProvidableCompositionLocal<Set<Any>>

The entry keys to render in the current Scene, in the sense of the target of the animation for an AnimatedContent that is transitioning between different scenes.

LocalNavAnimatedContentScope

val LocalNavAnimatedContentScopeProvidableCompositionLocal<AnimatedContentScope>

Local provider of AnimatedContentScope to androidx.navigation3.runtime.NavEntry.content.

This does not have a default value since the AnimatedContentScope is provided at runtime by AnimatedContent.

import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.runtime.remember
import androidx.navigation3.runtime.entry
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.ui.NavDisplay

val backStack = rememberNavBackStack(CatList)
SharedTransitionLayout {
    NavDisplay(
        backStack = backStack,
        onBack = { backStack.removeAt(backStack.lastIndex) },
        entryProvider =
            entryProvider {
                entry<CatList> {
                    CatList(this@SharedTransitionLayout) { cat ->
                        backStack.add(CatDetail(cat))
                    }
                }
                entry<CatDetail> { args ->
                    CatDetail(args.cat, this@SharedTransitionLayout) {
                        backStack.removeAt(backStack.lastIndex)
                    }
                }
            },
    )
}