Files
coco 723ce1af5c a
2026-07-03 15:12:48 +08:00

2.9 KiB

Multi-module navigation

Voyager has built-in support for multi-module navigation. Its API is based on great DI frameworks like Koin and Kodein, so should be familiar to use.

Suppose we have the following modules:

  • app: the entrypoint of our app, contains the Activity
  • feature-home: contains the root screen (HomeScreen)
  • feature-posts: contains screens related to the posts feature (ListScreen and DetailsScreen)
  • navigation: contains the screen providers used to navigate between modules, both feature-home and feature-posts imports it

To navigate from HomeScreen to the screens on feature-posts module (ListScreen and DetailsScreen), we first need to provide them. The navigation module should declare all shared screens in the app, use the ScreenProvider interface for that.

sealed class SharedScreen : ScreenProvider {
    object PostList : SharedScreen()
    data class PostDetails(val id: String) : SharedScreen()
}

Now use the ScreenRegistry to register these providers. This should be done in yourApplication class.

class MyApp : Application() {

    override fun onCreate() {
        super.onCreate()

        ScreenRegistry {
            register<SharedScreen.PostList> {
                ListScreen()
            }
            register<SharedScreen.PostDetails> { provider ->
                DetailsScreen(id = provider.id)
            }
        }
    }
}

You can also create a screenModule into your feature module, that way your Application class won't be bloated by too many declarations.

=== "ScreenModule"

```kotlin title="feature-posts/../ScreenModule.kt"
val featurePostsScreenModule = screenModule {
    register<SharedScreen.PostList> {
        ListScreen()
    }
    register<SharedScreen.PostDetails> { provider ->
        DetailsScreen(id = provider.id)
    }
}
```

```kotlin title="app/../MyApp.kt"
override fun onCreate() {
    super.onCreate()

    ScreenRegistry {
        featurePostsScreenModule()
    }
}
```

Finally, call rememberScreen() (inside a composable function) or ScreenRegistry.get() to access your screens.

class HomeScreen : Screen {

    @Composable
    override fun Content() {
        val navigator = LocalNavigator.currentOrThrow
        val postListScreen = rememberScreen(SharedScreen.PostList)
        val postDetailsScreen = rememberScreen(SharedScreen.PostDetails(id = postId))
        
        // navigator.push(postListScreen)
        // navigator.push(postDetailsScreen)
    }
}

Sample

!!! info Source code here.