Navigation Compose Typed
Compile-time type-safe arguments for JetPack Navigation Compose library. Based on KotlinX.Serialization.
Major features:
- Complex types support, including nullability for primitive types - the only condition is that the type has to be serializable with KotlinX.Serializable library.
- Based on official Kotlin Serialization compiler plugin - no slowdown with KSP nor KAPT.
- All JetPack Navigation Compose features: e.g.
navigateUp()
after a deeplink preserves the top-level shared arguments. - Few simple functions, no new complex
NavHost
orNavController
types; this allows covering other JetPack Navigation Compose extensions. - Gradual integration, feel free to onboard just a part of your app.
QuickStart
Add this library dependency and KotlinX.Serialization support
plugins {
id("org.jetbrains.kotlin.plugin.serialization") version "1.7.10"
}
dependencies {
implementation("com.kiwi.navigation-compose.typed:core:<version>")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0")
}
Warning This library uses Semantic Versioning. Be aware that BC breaks are allowed in minor versions before the major 1.0 version.
Create app's destinations
import com.kiwi.navigationcompose.typed.Destination
sealed interface Destinations : Destination {
@Serializable
object Home : Destinations
@Serializable
data class Article(
val id: String,
) : Destinations
}
and use them in the navigation graph definition
import com.kiwi.navigationcompose.typed.composable
import com.kiwi.navigationcompose.typed.createRoutePattern
NavGraph(
startDestination = createRoutePattern<Destinations.Home>(),
) {
composable<Destinations.Home> {
Home()
}
composable<Destinations.Article> {
// this is Destinations.Article
Article(id)
}
}
Now, it is time to navigate! Create a Destination
instance and pass it to the navigate extension method on the standard NavController
.
import com.kiwi.navigationcompose.typed.Destination
import com.kiwi.navigationcompose.typed.navigate
@Composable
fun AppNavHost() {
val navController = rememberNavController()
NavGraph(
navController = navController,
) {
composable<Destinations.Home> {
Home(navController::navigate)
}
}
}
@Composable
private fun Home(
onNavigate: (Destination) -> Unit,
) {
Home(
onArticleClick = { id -> onNavigate(Destinations.Article(id)) },
)
}
@Composable
private fun Home(
onArticleClick: (id: Int) -> Unit,
) {
Column {
Button(onClick = { onArticleClick(1) }) { Text("...") }
Button(onClick = { onArticleClick(2) }) { Text("...") }
}
}
Extensibility
What about cooperation with Accompanist's AnimatedNavHost
or bottomSheet {}
? Do not worry. Basically, all this are just few simple functions. Create your own abstraction and use createRoutePattern()
, createNavArguments()
, decodeArguments()
and registerDestinationType()
functions.
import com.kiwi.navigationcompose.typed.createRoutePattern
import com.kiwi.navigationcompose.typed.createNavArguments
import com.kiwi.navigationcompose.typed.decodeArguments
import com.kiwi.navigationcompose.typed.Destination
import com.kiwi.navigationcompose.typed.registerDestinationType
private inline fun <reified T : Destination> NavGraphBuilder.bottomSheet(
noinline content: @Composable T.(NavBackStackEntry) -> Unit,
) {
val serializer = serializer<T>()
registerDestinationType(T::class, serializer)
bottomSheet(
route = createRoutePattern(serializer),
arguments = createNavArguments(serializer),
) {
val arguments = decodeArguments(serializer, it)
arguments.content(it)
}
}
NavGraph {
bottomSheet<Destinations.Article> {
Article(id)
}
}