Skip to content

Commit 79db0fb

Browse files
Merge branch 'main' into dt/koin_nav3
# Conflicts: # app/src/main/java/com/example/nav3recipes/RecipePickerActivity.kt # gradle/libs.versions.toml
2 parents 86830bd + d8a6d49 commit 79db0fb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1369
-298
lines changed

README.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# Navigation 3 - Code recipes
22
[Jetpack Navigation 3](https://goo.gle/nav3) is a library for app navigation. This repository contains recipes for how to
3-
use its APIs to implement common navigation use cases.
3+
use its APIs to implement common navigation use cases. Each recipe introduces a single concept. Instead
4+
of making existing recipes more complex, there should be a new recipe for that particular concept.
5+
6+
Every Navigation 3 release will be an opportunity for patterns you see in recipes to "graduate" and become
7+
(optional) helpers in the library itself. Then we'll update the recipe to use that prebuilt helper, thus
8+
ensuring that the recipes continue to be a good way to approach these kinds of problems.
49

510
## Recipes
611
These are the recipes and what they demonstrate.
@@ -10,19 +15,23 @@ These are the recipes and what they demonstrate.
1015
- **[Saveable back stack](app/src/main/java/com/example/nav3recipes/basicsaveable)**: As above, with a persistent back stack.
1116
- **[Entry provider DSL](app/src/main/java/com/example/nav3recipes/basicdsl)**: As above, using the entryProvider DSL.
1217

13-
### Layouts and animations
14-
- **[Dialog](app/src/main/java/com/example/nav3recipes/dialog)**: Shows how to create a Dialog destination.
18+
### Layouts using Scenes
19+
- **[List-Detail Scene](app/src/main/java/com/example/nav3recipes/scenes/listdetail)**: Shows how to create a custom, list-detail layout using a `Scene` and `SceneStrategy` (see video of UI behavior below).
20+
- **[Two pane Scene](app/src/main/java/com/example/nav3recipes/scenes/twopane)**: Shows how to create a custom, 2-pane layout.
1521
- **[BottomSheet](app/src/main/java/com/example/nav3recipes/bottomsheet)**: Shows how to create a BottomSheet destination.
16-
- **[Custom Scene](app/src/main/java/com/example/nav3recipes/scenes/twopane)**: Shows how to create a custom layout using a `Scene` and `SceneStrategy` (see video of UI behavior below).
17-
- **[Animations](app/src/main/java/com/example/nav3recipes/animations)**: Override the default animations for all destinations and a single destination.
22+
- **[Dialog](app/src/main/java/com/example/nav3recipes/dialog)**: Shows how to create a Dialog.
1823

1924
### Material adaptive layouts
2025
Examples showing how to use the layouts provided by the [Compose Material3 Adaptive Navigation3 library](https://developer.android.com/jetpack/androidx/releases/compose-material3-adaptive#compose_material3_adaptive_navigation3_version_10_2)
2126
- **[List-Detail](app/src/main/java/com/example/nav3recipes/material/listdetail)**: Shows how to use a Material adaptive list-detail layout.
2227
- **[Supporting Pane](app/src/main/java/com/example/nav3recipes/material/supportingpane)**: Shows how to use a Material adaptive supporting pane layout.
2328

29+
### Animations
30+
- **[Animations](app/src/main/java/com/example/nav3recipes/animations)**: Shows how to override the default animations for all destinations and a single destination.
31+
2432
### Common use cases
25-
- **[Common navigation UI](app/src/main/java/com/example/nav3recipes/commonui)**: A common navigation toolbar where each item in the toolbar navigates to a top level destination.
33+
- **[Common navigation UI](app/src/main/java/com/example/nav3recipes/commonui)**: A common navigation toolbar where each item in the toolbar navigates to a top level destination.
34+
- **[Multiple back stacks](app/src/main/java/com/example/nav3recipes/multiplestacks)**: Shows how to create multiple top level routes, each with its own back stack. Top level routes are displayed in a navigation bar allowing users to switch between them. State is retained for each top level route, and the navigation state persists config changes and process death.
2635
- **[Conditional navigation](app/src/main/java/com/example/nav3recipes/conditional)**: Switch to a different navigation flow when a condition is met. For example, for authentication or first-time user onboarding.
2736

2837
### Architecture
@@ -43,9 +52,9 @@ Examples showing how to use the layouts provided by the [Compose Material3 Adapt
4352
- **Android XR**: Custom navigation and layout behavior for Android XR
4453

4554
## Custom layout example
46-
The following is a screen recording showing the navigation behavior of a [custom, two-pane Scene](app/src/main/java/com/example/nav3recipes/scenes/twopane).
55+
The following is a screen recording showing the navigation behavior of a [custom, list-detail Scene](app/src/main/java/com/example/nav3recipes/scenes/listdetail).
4756

48-
![Custom layout example](/docs/images/TwoPaneScene.gif)
57+
![Custom layout example](/docs/images/ListDetailScene.gif)
4958

5059
## Instructions
5160
Clone this repository and open the root folder in [Android Studio](https://developer.android.com/studio). Each recipe is contained in its own package with its own `Activity`.
@@ -56,6 +65,9 @@ If the issue is _directly related to this project_, as in, it's reproducible wit
5665
## Contributing
5766
We'd love to accept your contributions. Please follow [these instructions](CONTRIBUTING.md).
5867

68+
## Compose Multiplatform Recipes
69+
CMP recipes can be found [here](https://github.com/terrakok/nav3-recipes).
70+
5971
## License
6072
```
6173
Copyright 2025 The Android Open Source Project

app/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ plugins {
1818
alias(libs.plugins.android.application)
1919
alias(libs.plugins.kotlin.android)
2020
alias(libs.plugins.kotlin.compose)
21-
alias(libs.plugins.jetbrains.kotlin.serialization)
21+
alias(libs.plugins.kotlin.serialization)
2222
alias(libs.plugins.hilt)
2323
alias(libs.plugins.ksp)
2424
}

app/src/main/AndroidManifest.xml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,6 @@
7777
android:name=".material.supportingpane.MaterialSupportingPaneActivity"
7878
android:exported="true"
7979
android:theme="@style/Theme.Nav3Recipes"/>
80-
<activity
81-
android:name=".scenes.twopane.TwoPaneActivity"
82-
android:exported="true"
83-
android:theme="@style/Theme.Nav3Recipes"/>
8480
<activity
8581
android:name=".animations.AnimatedActivity"
8682
android:exported="true"
@@ -150,6 +146,18 @@
150146
android:name=".migration.step7.Step7MigrationActivity"
151147
android:exported="true"
152148
android:theme="@style/Theme.Nav3Recipes"/>
149+
<activity
150+
android:name=".scenes.twopane.TwoPaneActivity"
151+
android:exported="true"
152+
android:theme="@style/Theme.Nav3Recipes"/>
153+
<activity
154+
android:name=".scenes.listdetail.ListDetailActivity"
155+
android:exported="true"
156+
android:theme="@style/Theme.Nav3Recipes"/>
157+
<activity
158+
android:name=".multiplestacks.MultipleStacksActivity"
159+
android:exported="true"
160+
android:theme="@style/Theme.Nav3Recipes"/>
153161
</application>
154162

155163
</manifest>

app/src/main/java/com/example/nav3recipes/RecipePickerActivity.kt

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
/*
2+
* Copyright 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
117
package com.example.nav3recipes
218

319
import android.app.Activity
@@ -33,15 +49,17 @@ import com.example.nav3recipes.bottomsheet.BottomSheetActivity
3349
import com.example.nav3recipes.commonui.CommonUiActivity
3450
import com.example.nav3recipes.conditional.ConditionalActivity
3551
import com.example.nav3recipes.dialog.DialogActivity
52+
import com.example.nav3recipes.material.listdetail.MaterialListDetailActivity
53+
import com.example.nav3recipes.material.supportingpane.MaterialSupportingPaneActivity
54+
import com.example.nav3recipes.multiplestacks.MultipleStacksActivity
3655
import com.example.nav3recipes.modular.hilt.HiltModularActivity
3756
import com.example.nav3recipes.modular.koin.KoinModularActivity
3857
import com.example.nav3recipes.passingarguments.viewmodels.basic.BasicViewModelsActivity
3958
import com.example.nav3recipes.passingarguments.viewmodels.hilt.HiltViewModelsActivity
4059
import com.example.nav3recipes.passingarguments.viewmodels.koin.KoinViewModelsActivity
41-
import com.example.nav3recipes.material.listdetail.MaterialListDetailActivity
42-
import com.example.nav3recipes.material.supportingpane.MaterialSupportingPaneActivity
4360
import com.example.nav3recipes.results.event.ResultEventActivity
4461
import com.example.nav3recipes.results.state.ResultStateActivity
62+
import com.example.nav3recipes.scenes.listdetail.ListDetailActivity
4563
import com.example.nav3recipes.scenes.twopane.TwoPaneActivity
4664
import com.example.nav3recipes.ui.setEdgeToEdgeConfig
4765

@@ -61,17 +79,22 @@ private val recipes = listOf(
6179
Recipe("Basic DSL", BasicDslActivity::class.java),
6280
Recipe("Basic Saveable", BasicSaveableActivity::class.java),
6381

64-
Heading("Layouts and animations"),
82+
Heading("Layouts using Scenes"),
83+
Recipe("List-detail", ListDetailActivity::class.java),
84+
Recipe("Two pane", TwoPaneActivity::class.java),
6585
Recipe("Bottom Sheet", BottomSheetActivity::class.java),
66-
Recipe("Material list-detail layout", MaterialListDetailActivity::class.java),
67-
Recipe("Material supporting-pane layout", MaterialSupportingPaneActivity::class.java),
6886
Recipe("Dialog", DialogActivity::class.java),
87+
88+
Heading("Material adaptive layouts"),
6989
Recipe("Material list-detail layout", MaterialListDetailActivity::class.java),
70-
Recipe("Two pane layout (custom scene)", TwoPaneActivity::class.java),
71-
Recipe("Animations", AnimatedActivity::class.java),
90+
Recipe("Material supporting-pane layout", MaterialSupportingPaneActivity::class.java),
91+
92+
Heading("Animations"),
93+
Recipe("NavDisplay and NavEntry animations", AnimatedActivity::class.java),
7294

7395
Heading("Common use cases"),
7496
Recipe("Common UI", CommonUiActivity::class.java),
97+
Recipe("Multiple Stacks", MultipleStacksActivity::class.java),
7598
Recipe("Conditional navigation", ConditionalActivity::class.java),
7699

77100
Heading("Architecture"),

app/src/main/java/com/example/nav3recipes/animations/AnimatedActivity.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ import com.example.nav3recipes.ui.setEdgeToEdgeConfig
2525
import kotlinx.serialization.Serializable
2626

2727

28-
/**
29-
* This recipe shows how to override the default animations at the `NavDisplay` level, and at the
30-
* individual destination level, shown for `ScreenC`.
31-
*
32-
*/
3328
@Serializable
3429
private data object ScreenA : NavKey
3530

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Animations Recipe
2+
3+
This recipe shows how to override the default animations at the `NavDisplay` level, and at the individual destination level.
4+
5+
## How it works
6+
7+
The `NavDisplay` composable takes `transitionSpec`, `popTransitionSpec`, and `predictivePopTransitionSpec` parameters to define the animations for forward, backward, and predictive back navigation respectively. These animations will be applied to all destinations by default.
8+
9+
In this example, we use `slideInHorizontally` and `slideOutHorizontally` to create a sliding animation for forward and backward navigation.
10+
11+
It is also possible to override these animations for a specific destination by providing a different `transitionSpec` and `popTransitionSpec` to the `entry` composable. In this recipe, `ScreenC` has a custom vertical slide animation.

app/src/main/java/com/example/nav3recipes/basic/BasicActivity.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@ import com.example.nav3recipes.content.ContentBlue
2929
import com.example.nav3recipes.content.ContentGreen
3030
import com.example.nav3recipes.ui.setEdgeToEdgeConfig
3131

32-
/**
33-
* Basic example with two screens, showing how to use the Navigation 3 API.
34-
*/
35-
3632
private data object RouteA
3733

3834
private data class RouteB(val id: String)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Basic Recipe
2+
3+
This recipe shows a basic example of how to use the Navigation 3 API with two screens.
4+
5+
## How it works
6+
7+
This example defines two routes: `RouteA` and `RouteB`. `RouteA` is a `data object` representing a simple screen, while `RouteB` is a `data class` that takes an `id` as a parameter.
8+
9+
A `mutableStateListOf<Any>` is used to manage the navigation back stack.
10+
11+
The `NavDisplay` composable is used to display the current screen. Its `entryProvider` parameter is a lambda that takes a route from the back stack and returns a `NavEntry`. Inside the `entryProvider`, a `when` statement is used to determine which composable to display based on the route.
12+
13+
To navigate from `RouteA` to `RouteB`, we simply add a `RouteB` instance to the back stack. The `id` is passed as an argument to the `RouteB` data class.

app/src/main/java/com/example/nav3recipes/basicdsl/BasicDslActivity.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ import com.example.nav3recipes.content.ContentGreen
3030
import com.example.nav3recipes.ui.setEdgeToEdgeConfig
3131
import kotlinx.serialization.Serializable
3232

33-
/**
34-
* Basic example with two screens that uses the entryProvider DSL and has a persistent back stack.
35-
*/
36-
3733
@Serializable
3834
private data object RouteA : NavKey
3935

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Basic DSL Recipe
2+
3+
This recipe shows a basic example of how to use the Navigation 3 API with two screens, using the `entryProvider` DSL and a persistent back stack.
4+
5+
## How it works
6+
7+
This example is similar to the basic recipe, but with a few key differences:
8+
9+
1. **Persistent Back Stack**: It uses `rememberNavBackStack(RouteA)` to create and remember the back stack. This makes the back stack persistent across configuration changes (e.g., screen rotation). To use `rememberNavBackStack`, the navigation keys must be serializable, which is why `RouteA` and `RouteB` are annotated with `@Serializable` and implement the `NavKey` interface.
10+
11+
2. **`entryProvider` DSL**: Instead of a `when` statement, this example uses the `entryProvider` DSL to define the content for each route. The `entry<RouteType>` function is used to associate a route type with its composable content.
12+
13+
The navigation logic remains the same: to navigate from `RouteA` to `RouteB`, we add a `RouteB` instance to the back stack.

0 commit comments

Comments
 (0)