Navigation 3 Recipes

repository·master·Indexed 42 days ago

https://github.com/terrakok/nav3-recipes

A collection of implementation patterns and recipes for Navigation 3, demonstrating UI behaviors such as modal bottom sheets, custom layouts, and transitions. Includes guides on using NavDisplay, implementing persistent back stacks with rememberNavBackStack, and managing multi-stack navigation with TopLevelBackStack for bottom navigation bars. Supports Android, iOS, Desktop, and Web (JS and Wasm) targets.

Tokens
16K
Snippets
39
Records
80
Agent score
53%

What's inside Navigation 3 Recipes

  1. Implement conditional navigation with the Conditional Navigation Recipe

    master

    The Conditional Navigation Recipe provides a pattern for restricting access to specific destinations based on application state (e.g., authentication).

    In this pattern, a custom AppBackStack manages the navigation logic. If a user attempts to navigate to a destination that implements the RequiresLogin marker interface while not authenticated, the system automatically redirects them to a Login screen. Once authentication is successful, the system can automatically redirect the user back to their intended destination.

  2. Implement a Bottom Navigation pattern with multiple back stacks

    master

    This recipe provides a pattern for implementing a common navigation UI where a bottom navigation bar manages multiple top-level destinations (tabs), each maintaining its own independent navigation history.

    Key components include:

    • A NavigationBar to switch between tabs.
    • A TopLevelBackStack to manage the individual histories.
    • A NavDisplay composable to render the current screen based on the combined state.
  3. How Dialog Scene Decoration works

    master

    Dialog decoration is a transformation process where a standard Scene is intercepted by a SceneDecorationStrategy and rendered as a DialogDecoratorScene.

    Key components of this mental model include:

    • DialogSceneMetadataKey: A metadata marker used to signal that a scene is eligible to be rendered as a dialog.
    • DialogDecoratorSceneConfiguration: A configuration object used to define dismissal behaviors (e.g., whether a click-outside event should clear the entire scene or just a single entry).
    • DialogSceneDecoratorStrategy: The logic engine that evaluates the window state and scene metadata to decide if the decoration should be applied.
    • NavDisplay Integration: The central component where these strategies are registered to intercept scene transitions.
  4. Implement a persistent back stack with `rememberNavBackStack`

    master

    To ensure your navigation state is preserved during configuration changes, use rememberNavBackStack.

    Constraints:

    • Your route classes must implement the NavKey interface.
    • Your route classes must be annotated with @Serializable (e.g., using Kotlinx Serialization) to allow the back stack to be serialized and restored.
    @Serializable
    object RouteA : NavKey
    
    @Serializable
    data class RouteB(val id: String) : NavKey
    
    // Usage in Composable
    val backStack = rememberNavBackStack(RouteA)
  5. Understand state preservation and back button behavior

    master

    In this specific implementation, navigation state is managed with the following behaviors:

    • History Clearing: When a user navigates away from a top-level destination (for example, by pressing the back button until they return to a previous tab), the entire navigation history for the destination they left is cleared. State is not preserved for that tab.
    • Re-entry: When a user returns to a previously visited tab, they will start from its initial screen rather than their previous position.
    • App Exit: The app exits when the user navigates back from the last remaining top-level route in the back stack. Note that certain routes (like Home in the example) may be configured to move above other routes in the stack, affecting the exit flow.
  6. How DialogSceneStrategy works

    master

    The DialogSceneStrategy is a mechanism in Navigation 3 that intercepts navigation to specific destinations and renders them in a dialog window rather than a full-screen layout.

    It works by combining a global strategy provided to NavDisplay with destination-specific metadata. When the navigator attempts to move to a destination that contains DialogSceneStrategy.dialog() in its metadata, the NavDisplay uses the provided strategy to trigger a dialog presentation.

  7. How ListDetailSceneStrategy manages pane roles and layout

    master

    The ListDetailSceneStrategy uses a role-based system to determine how destinations are rendered in an adaptive layout.

    Pane Roles

    • List Pane: The primary content. It is always visible in multi-pane layouts. If no detail is selected, a placeholder can be used.
    • Detail Pane: The secondary content that appears alongside the list on wider screens.
    • Extra Pane: Tertiary content that appears on very wide screens.

    Adaptive Behavior

    • Small Screens: Only one pane is shown at a time.
    • Medium/Wide Screens: Shows the list and detail panes side-by-side.
    • Very Wide Screens: Shows all three panes: list, detail, and extra.

    Navigation works by adding or removing destinations from the back stack. The strategy monitors the back stack to decide which panes to show or hide based on the current navigation state and screen width.

  8. How `TopLevelBackStack` manages navigation state

    master

    The TopLevelBackStack class is the central coordinator for multi-stack navigation. It performs three main functions:

    1. Individual Back Stacks: It maintains a separate back stack for every top-level destination (tab).
    2. Tab Tracking: It tracks which top-level destination is currently selected.
    3. Flattened Back Stack: It provides a single, flattened back stack to the NavDisplay composable. This flattened stack is a combination of the individual back stacks from all tabs, allowing the system to treat the entire multi-stack structure as a single navigable sequence.
  9. How `NavigationScene` handles shared UI and transitions

    master

    When transitioning between scenes, both the outgoing and incoming scenes are composed and rendered simultaneously. To prevent shared UI elements (like Nav Bars) from being composed twice or losing internal state (like selection animations), the NavigationScene uses a combination of two Compose APIs:

    • movableContentOf: Retains the state of the navigation composables as they move between different branches of the composition tree during scene transitions.
    • Shared Element APIs: Uses the sharedElement modifier and a custom cacheSize modifier. The cacheSize modifier maintains a placeholder of the correct size in the scene that does not call the movable content composable, allowing the actual navigation element to stay visually in place while the scene content animates.
  10. How NavDisplay and entryProvider work together

    master

    In Navigation 3, NavDisplay is the primary composable for rendering the current navigation state. It relies on the entryProvider parameter to resolve routes into UI.

    The entryProvider is a lambda function that receives the current route (the top item of your back stack) and must return a NavEntry. This pattern decouples the navigation state (the list of routes) from the UI implementation (the Composables), allowing you to use standard Kotlin control flow like when to handle routing logic.

  11. Configure back navigation for Supporting Pane layouts

    master

    When using a supporting pane, you must decide how the back button behaves. In this recipe, the BackNavigationBehavior is set to PopUntilCurrentDestinationChange.

    With this configuration, when a user is viewing a supporting pane and presses the back button, the supporting pane is dismissed, revealing the main pane that was underneath it, rather than navigating away from the entire screen context.

  12. How ResultStore manages state-based results

    master

    The ResultStore pattern works by decoupling the producer of a result from the consumer through a shared state container.

    • ResultStore: Acts as the single source of truth for the result data.
    • setResult(value): A method used by the 'producer' screen to push new data into the store.
    • getResultState<T?>(): A method used by the 'consumer' screen to subscribe to the result. It returns a Compose State object, ensuring that the consumer's UI stays in sync with the store's contents.