NavDisplayKt

Added in 1.0.0-alpha11

public final class NavDisplayKt


Summary

Public methods

static final void
@Composable
<T extends Object> NavDisplay(
    @NonNull SceneState<@NonNull T> sceneState,
    @NonNull NavigationEventState<@NonNull SceneInfo<@NonNull T>> navigationEventState,
    @NonNull Modifier modifier,
    @NonNull Alignment contentAlignment,
    SizeTransform sizeTransform,
    @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> transitionSpec,
    @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> popTransitionSpec,
    @NonNull Function2<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull Integer, @NonNull ContentTransform> predictivePopTransitionSpec
)

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

static final void
@Composable
<T extends Object> NavDisplay(
    @NonNull List<@NonNull NavEntry<@NonNull T>> entries,
    @NonNull Modifier modifier,
    @NonNull Alignment contentAlignment,
    @NonNull SceneStrategy<@NonNull T> sceneStrategy,
    SizeTransform sizeTransform,
    @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> transitionSpec,
    @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> popTransitionSpec,
    @NonNull Function2<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull Integer, @NonNull ContentTransform> predictivePopTransitionSpec,
    @NonNull Function0<Unit> onBack
)

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

static final void
@Composable
<T extends Object> NavDisplay(
    @NonNull List<@NonNull T> backStack,
    @NonNull Modifier modifier,
    @NonNull Alignment contentAlignment,
    @NonNull Function0<Unit> onBack,
    @NonNull List<@NonNull NavEntryDecorator<@NonNull T>> entryDecorators,
    @NonNull SceneStrategy<@NonNull T> sceneStrategy,
    SizeTransform sizeTransform,
    @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> transitionSpec,
    @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> popTransitionSpec,
    @NonNull Function2<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull Integer, @NonNull ContentTransform> predictivePopTransitionSpec,
    @NonNull Function1<@NonNull key, @NonNull NavEntry<@NonNull T>> entryProvider
)

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

static final @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform>

Default transitionSpec for pop navigation to be used by NavDisplay.

static final @NonNull Function2<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull Integer, @NonNull ContentTransform>

Default transitionSpec for predictive pop navigation to be used by NavDisplay.

static final @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform>

Default transitionSpec for forward navigation to be used by NavDisplay.

Public methods

@Composable
public static final void <T extends Object> NavDisplay(
    @NonNull SceneState<@NonNull T> sceneState,
    @NonNull NavigationEventState<@NonNull SceneInfo<@NonNull T>> navigationEventState,
    @NonNull Modifier modifier,
    @NonNull Alignment contentAlignment,
    SizeTransform sizeTransform,
    @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> transitionSpec,
    @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> popTransitionSpec,
    @NonNull Function2<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull Integer, @NonNull ContentTransform> predictivePopTransitionSpec
)

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

By default, AnimatedContent transitions are prioritized in this order:

transitioning [NavEntry.metadata] current [Scene.metadata] NavDisplay defaults

However, a Scene.metadata does have the ability to override NavEntry.metadata. Nevertheless, the final fallback will always be the NavDisplay's default transitions.

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.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
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.navigationevent.NavigationEvent

val backStack = rememberNavBackStack(Profile)
val showDialog = remember { mutableStateOf(false) }
NavDisplay(
    backStack = backStack,
    entryDecorators =
        listOf(
            rememberSaveableStateHolderNavEntryDecorator(),
            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 { swipeEdge ->
                        if (swipeEdge == NavigationEvent.EDGE_RIGHT) {
                            slideInHorizontally(tween(700)) { it / 2 } togetherWith
                                slideOutHorizontally(tween(700)) { -it / 2 }
                        } else {
                            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.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
import androidx.navigation3.scene.Scene
import androidx.navigation3.ui.LocalNavAnimatedContentScope
import androidx.navigation3.ui.NavDisplay

/** 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<Any> { entry ->
        with(localNavSharedTransitionScope.current) {
            Box(
                Modifier.sharedElement(
                    rememberSharedContentState(entry.contentKey),
                    animatedVisibilityScope = LocalNavAnimatedContentScope.current,
                )
            ) {
                entry.Content()
            }
        }
    }

val backStack = rememberNavBackStack(CatList)
SharedTransitionLayout {
    CompositionLocalProvider(localNavSharedTransitionScope provides this) {
        NavDisplay(
            backStack = backStack,
            onBack = { backStack.removeAt(backStack.lastIndex) },
            entryDecorators =
                listOf(
                    sharedEntryInSceneNavEntryDecorator,
                    rememberSaveableStateHolderNavEntryDecorator(),
                ),
            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.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
@NonNull SceneState<@NonNull T> sceneState

the state that determines what current scene of the NavDisplay.

@NonNull NavigationEventState<@NonNull SceneInfo<@NonNull T>> navigationEventState

the NavigationEventState responsible for handling back navigation

@NonNull Modifier modifier

the modifier to be applied to the layout.

@NonNull Alignment contentAlignment

The Alignment of the AnimatedContent

SizeTransform sizeTransform

the SizeTransform for the AnimatedContent.

@NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> transitionSpec

Default ContentTransform when navigating to NavEntrys.

@NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> popTransitionSpec

Default ContentTransform when popping NavEntrys.

@NonNull Function2<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull Integer, @NonNull ContentTransform> predictivePopTransitionSpec

Default ContentTransform when popping with predictive back NavEntrys.

@Composable
public static final void <T extends Object> NavDisplay(
    @NonNull List<@NonNull NavEntry<@NonNull T>> entries,
    @NonNull Modifier modifier,
    @NonNull Alignment contentAlignment,
    @NonNull SceneStrategy<@NonNull T> sceneStrategy,
    SizeTransform sizeTransform,
    @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> transitionSpec,
    @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> popTransitionSpec,
    @NonNull Function2<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull Integer, @NonNull ContentTransform> predictivePopTransitionSpec,
    @NonNull Function0<Unit> onBack
)

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.

By default, AnimatedContent transitions are prioritized in this order:

transitioning [NavEntry.metadata] current [Scene.metadata] NavDisplay defaults

However, a Scene.metadata does have the ability to override NavEntry.metadata. Nevertheless, the final fallback will always be the NavDisplay's default transitions.

WHEN TO USE This overload can be used when you need to switch between different backStacks and each with their own separate decorator states, or when you want to concatenate backStacks and their states to form a larger backstack.

HOW TO USE The entries can first be created via rememberDecoratedNavEntries in order to associate a backStack with a particular set of states.

import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.navigation3.runtime.NavBackStack
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.ui.NavDisplay

val tabKeys = listOf(Home, User)

/** set up User entries */
val homeBackStack = rememberNavBackStack(Home)
val homeTabEntries =
    getHomeTabEntries(
        backStackString = homeBackStack.map { (it as SampleKey).name }.toString(),
        backStack = homeBackStack,
    )

/** set up User entries */
val userBackStack = rememberNavBackStack(User)
val userTabEntries =
    getUserTabEntries(
        backStackString = userBackStack.map { (it as SampleKey).name }.toString(),
        backStack = userBackStack,
    )

/** condition for which tab to switch to */
var currentTab: SampleTabKey by remember { mutableStateOf(Home) }

Scaffold(
    bottomBar = {
        NavigationBar {
            tabKeys.forEach { tab ->
                val isSelected = tab == currentTab
                NavigationBarItem(
                    selected = isSelected,
                    onClick = { currentTab = tab },
                    icon = { Icon(imageVector = tab.imageVector, contentDescription = null) },
                )
            }
        }
    }
) {
    /** Swap backStacks based on the current selected tab */
    NavDisplay(
        entries = if (currentTab == Home) homeTabEntries else userTabEntries,
        onBack = {
            val currBackStack = if (currentTab == Home) homeBackStack else userBackStack
            currBackStack.removeLastOrNull()
        },
    )
}
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.navigation3.runtime.NavBackStack
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.ui.NavDisplay

val tabKeys = listOf(Home, User)

/** set up User entries */
val homeBackStack = rememberNavBackStack(Home)
val homeBackStackNames = homeBackStack.map { (it as SampleKey).name }
val homeTabEntries =
    getHomeTabEntries(
        backStackString = homeBackStackNames.toString(),
        backStack = homeBackStack,
    )

/** set up User entries */
val userBackStack = rememberNavBackStack(User)
val userTabEntries =
    getUserTabEntries(
        backStackString =
            (homeBackStackNames + userBackStack.map { (it as SampleKey).name }).toString(),
        backStack = userBackStack,
    )

/** condition for which tab to switch to */
var currentTab: SampleTabKey by remember { mutableStateOf(Home) }

Scaffold(
    bottomBar = {
        NavigationBar {
            tabKeys.forEach { tab ->
                val isSelected = tab == currentTab
                NavigationBarItem(
                    selected = isSelected,
                    onClick = { currentTab = tab },
                    icon = { Icon(imageVector = tab.imageVector, contentDescription = null) },
                )
            }
        }
    }
) {
    /** Swap backStacks based on the current selected tab */
    NavDisplay(
        entries = if (currentTab == Home) homeTabEntries else homeTabEntries + userTabEntries,
        onBack = {
            val currBackStack = if (currentTab == Home) homeBackStack else userBackStack
            currBackStack.removeLastOrNull()
            if (currentTab == User && userBackStack.isEmpty()) {
                currentTab = Home
            }
        },
    )
}
Parameters
@NonNull List<@NonNull NavEntry<@NonNull T>> entries

the list of NavEntry built from a backStack. The entries can be created from a backStack decorated with NavEntryDecorator via rememberDecoratedNavEntries.

@NonNull Modifier modifier

the modifier to be applied to the layout.

@NonNull Alignment contentAlignment

The Alignment of the AnimatedContent

@NonNull SceneStrategy<@NonNull T> sceneStrategy

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

SizeTransform sizeTransform

the SizeTransform for the AnimatedContent.

@NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> transitionSpec

Default ContentTransform when navigating to NavEntrys.

@NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> popTransitionSpec

Default ContentTransform when popping NavEntrys.

@NonNull Function2<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull Integer, @NonNull ContentTransform> predictivePopTransitionSpec

Default ContentTransform when popping with predictive back NavEntrys.

@NonNull Function0<Unit> onBack

a callback for handling system back press.

@Composable
public static final void <T extends Object> NavDisplay(
    @NonNull List<@NonNull T> backStack,
    @NonNull Modifier modifier,
    @NonNull Alignment contentAlignment,
    @NonNull Function0<Unit> onBack,
    @NonNull List<@NonNull NavEntryDecorator<@NonNull T>> entryDecorators,
    @NonNull SceneStrategy<@NonNull T> sceneStrategy,
    SizeTransform sizeTransform,
    @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> transitionSpec,
    @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> popTransitionSpec,
    @NonNull Function2<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull Integer, @NonNull ContentTransform> predictivePopTransitionSpec,
    @NonNull Function1<@NonNull key, @NonNull NavEntry<@NonNull T>> entryProvider
)

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.

By default, AnimatedContent transitions are prioritized in this order:

transitioning [NavEntry.metadata] current [Scene.metadata] NavDisplay defaults

However, a Scene.metadata does have the ability to override NavEntry.metadata. Nevertheless, the final fallback will always be the NavDisplay's default transitions.

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.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
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.navigationevent.NavigationEvent

val backStack = rememberNavBackStack(Profile)
val showDialog = remember { mutableStateOf(false) }
NavDisplay(
    backStack = backStack,
    entryDecorators =
        listOf(
            rememberSaveableStateHolderNavEntryDecorator(),
            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 { swipeEdge ->
                        if (swipeEdge == NavigationEvent.EDGE_RIGHT) {
                            slideInHorizontally(tween(700)) { it / 2 } togetherWith
                                slideOutHorizontally(tween(700)) { -it / 2 }
                        } else {
                            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.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
import androidx.navigation3.scene.Scene
import androidx.navigation3.ui.LocalNavAnimatedContentScope
import androidx.navigation3.ui.NavDisplay

/** 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<Any> { entry ->
        with(localNavSharedTransitionScope.current) {
            Box(
                Modifier.sharedElement(
                    rememberSharedContentState(entry.contentKey),
                    animatedVisibilityScope = LocalNavAnimatedContentScope.current,
                )
            ) {
                entry.Content()
            }
        }
    }

val backStack = rememberNavBackStack(CatList)
SharedTransitionLayout {
    CompositionLocalProvider(localNavSharedTransitionScope provides this) {
        NavDisplay(
            backStack = backStack,
            onBack = { backStack.removeAt(backStack.lastIndex) },
            entryDecorators =
                listOf(
                    sharedEntryInSceneNavEntryDecorator,
                    rememberSaveableStateHolderNavEntryDecorator(),
                ),
            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.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
@NonNull List<@NonNull T> backStack

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

@NonNull Modifier modifier

the modifier to be applied to the layout.

@NonNull Alignment contentAlignment

The Alignment of the AnimatedContent

@NonNull Function0<Unit> onBack

a callback for handling system back press. By default, this pops a single item off of the given back stack if it is a MutableList, otherwise you should provide this parameter.

@NonNull List<@NonNull NavEntryDecorator<@NonNull T>> entryDecorators

list of NavEntryDecorator to add information to the entry content

@NonNull SceneStrategy<@NonNull T> sceneStrategy

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

SizeTransform sizeTransform

the SizeTransform for the AnimatedContent.

@NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> transitionSpec

Default ContentTransform when navigating to NavEntrys.

@NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> popTransitionSpec

Default ContentTransform when popping NavEntrys.

@NonNull Function2<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull Integer, @NonNull ContentTransform> predictivePopTransitionSpec

Default ContentTransform when popping with predictive back NavEntrys.

@NonNull Function1<@NonNull key, @NonNull NavEntry<@NonNull T>> entryProvider

lambda used to construct each possible NavEntry

defaultPopTransitionSpec

public static final @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> <T extends Object> defaultPopTransitionSpec()

Default transitionSpec for pop navigation to be used by NavDisplay.

defaultPredictivePopTransitionSpec

public static final @NonNull Function2<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull Integer, @NonNull ContentTransform> <T extends Object> defaultPredictivePopTransitionSpec()

Default transitionSpec for predictive pop navigation to be used by NavDisplay.

defaultTransitionSpec

public static final @NonNull Function1<@NonNull AnimatedContentTransitionScope<@NonNull Scene<@NonNull T>>, @NonNull ContentTransform> <T extends Object> defaultTransitionSpec()

Default transitionSpec for forward navigation to be used by NavDisplay.