Compose Multiplatform Navigation - Pragmatic, type safety navigation for Compose Multiplatform. Based on Freeletics Navigation.
-
Integrate with
Jetpack Compose
andCompose Multiplatform
seamlessly. -
Integrate with kmp-viewmodel library seamlessly
- Stack entry scoped
ViewModel
, exists as long as the stack entry is on the navigation stack, including the configuration changes onAndroid
. - Supports
SavedStateHandle
, used to save and restore data over configuration changes or process death onAndroid
.
- Stack entry scoped
-
Type safety navigation, easy to pass data between destinations.
-
Supports Multi-Backstacks, this is most commonly used in apps that use bottom navigation to separate the back stack of each tab. See Freeletics Navigation - Multiple back stacks.
-
Supports
Lifecycle
events, similar toAndroidX Lifecycle
library.
-
Most of code in
solivagant-khonshu-navigation-core
andsolivagant-navigation
libraries is taken from Freeletics Navigation, and ported toKotlin Multiplatform
andCompose Multiplatform
. -
The
solivagant-lifecycle
library is inspired by Essenty Lifecycle, and AndroidX Lifecycle.
Author: Petrus Nguyễn Thái Học
Liked some of my work? Buy me a coffee (or more likely a beer)
0.x release docs: https://hoc081098.github.io/solivagant/docs/0.x
Snapshot docs: https://hoc081098.github.io/solivagant/docs/latest
allprojects { repositories { [...] mavenCentral() } }
implementation("io.github.hoc081098:solivagant-navigation:0.0.1-alpha01")
- The concept is similar to
Freeletics Navigation
library, so you can read the Freeletics Navigation to understand the concept.
@Immutable @Parcelize data object StartScreenRoute : NavRoute, NavRoot @Immutable @Parcelize data object SearchProductScreenRoute : NavRoute
@JvmField val StartScreenDestination: NavDestination = ScreenDestination<StartScreenRoute> { StartScreen() } @Composable internal fun StartScreen( modifier: Modifier = Modifier, viewModel: StartViewModel = koinKmpViewModel(), ) { // UI Composable } class StartViewModel( // used to trigger navigation actions from outside the view layer (e.g. from a ViewModel). // Usually, it is singleton object, or the host Activity retained scope. private val navigator: NavEventNavigator, ) : ViewModel() { internal fun navigateToProductsScreen() = navigator.navigateTo(ProductsScreenRoute) internal fun navigateToSearchProductScreen() = navigator.navigateTo(SearchProductScreenRoute) }
@JvmField val SearchProductScreenDestination: NavDestination = ScreenDestination<SearchProductScreenRoute> { SearchProductsScreen() } @Composable fun SearchProductsScreen( modifier: Modifier = Modifier, viewModel: SearchProductsViewModel = koinKmpViewModel<SearchProductsViewModel>(), ) { // UI Composable } class SearchProductsViewModel( private val searchProducts: SearchProducts, private val savedStateHandle: SavedStateHandle, // used to trigger navigation actions from outside the view layer (e.g. from a ViewModel). // Usually, it is singleton object, or the host Activity retained scope. private val navigator: NavEventNavigator, ) : ViewModel() { fun navigateToProductDetail(id: Int) { navigator.navigateTo(ProductDetailScreenRoute(id)) } }
@Stable private val AllDestinations: ImmutableSet<NavDestination> = persistentSetOf( StartScreenDestination, SearchProductScreenDestination, // and more ... ) @Composable fun MyAwesomeApp( // used to trigger navigation actions from outside the view layer (e.g. from a ViewModel). // Usually, it is singleton object, or the host Activity retained scope. navigator: NavEventNavigator, modifier: Modifier = Modifier, ) { var currentRoute: BaseRoute? by remember { mutableStateOf(null) } NavHost( modifier = modifier, // route to the screen that should be shown initially startRoute = StartScreenRoute, // should contain all destinations that can be navigated to destinations = AllDestinations, navEventNavigator = navigator, destinationChangedCallback = { currentRoute = it }, ) }
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle) { super.onCreate() // navigator can be retrieved from the DI container, such as Koin, Dagger Hilt, etc. setContent { MyAwesomeApp( navigator = navigator ) } } }
// navigate to the destination that the given route leads to navigator.navigateTo(DetailScreenRoute("some-id")) // navigate up in the hierarchy navigator.navigateUp() // navigate to the previous destination in the backstack navigator.navigateBack() // navigate back to the destination belonging to the referenced route and remove all destinations // in between from the back stack, depending on inclusive the destination navigator.navigateBackTo<MainScreenRoute>(inclusive = false)
- Samples sample: a complete sample using
Compose Multiplatform (Android, Desktop, iOS)
solivagant-navigation
for navigation in Compose Multiplatform.kmp-viewmodel
to shareViewModel
andSavedStateHandle
.Koin DI
.
- Add more tests
- Support transition when navigating
Apache License Version 2.0, January 2004 http://www.apache.org/licenses/