Navigation
🧪 Create Navigation between composable screens
Compose multiplatform navigation library enable a navigation with navigation host
Add Navigation
dependency to your project
gradle.build.kts (module : composeApp)
...
commonMain.dependencies {
plugins {
...
alias(libs.plugins.kotlinSerialization)
}
commonMain.dependencies {
...
implementation(libs.kotlin.navigation)
implementation(libs.ktor.serialization.kotlinx.json)
...
Create your navigation host
The navigation host is the configuration class that defines routes of your application.
Routes are path between all the composable screens that you will call later on your app.
For this Hands-on Lab we need 3 routes for :
- At startup to the
WelcomeScreen
- from Welcome screen to the
QuizScreen
- from the final question
QuizScreen
to theScoreScreen
App.kt (SourceSet: commonMain)
...
import kotlinx.serialization.Serializable
val questions = listOf(
Question(
1,
"Android is a great platform ?",
1,
listOf(Answer(1, "YES"), Answer(2, "NO"))
),
Question(
1,
"Android is a bad platform ?",
2,
listOf(Answer(1, "YES"), Answer(2, "NO"))
)
)
@Serializable
object WelcomeRoute
@Serializable
object QuizRoute
@Serializable
data class ScoreRoute(val score: Int, val questionSize: Int)
@Composable
fun App(
navController: NavHostController = rememberNavController()
) {
MaterialTheme {
NavHost(
navController = navController,
startDestination = WelcomeRoute,
) {
composable<WelcomeRoute> {
welcomeScreen(
onStartButtonPushed = {
navController.navigate(route = QuizRoute)
}
)
}
composable<QuizRoute> {
questionScreen(
questions = questions,
/* FOR SPEAKER TALK DEMO ON WEB APP */
onFinishButtonPushed = {
score: Int, questionSize: Int -> navController.navigate(route = ScoreRoute(score, questionSize))
}
)
}
composable<ScoreRoute> { backStackEntry ->
val scoreRoute: ScoreRoute = backStackEntry.toRoute<ScoreRoute>()
scoreScreen(
score = scoreRoute.score,
total = scoreRoute.questionSize,
onResetButtonPushed = {
navController.navigate(route = QuizRoute)
}
)
}
}
}
}
Warning
As you can see all composables now take as parameter a navigator. It will be needed to navigate with routes between screens.
for example, the WelcomeScreen
composable is now declared as follows :
@Composable()
fun welcomeScreen(navigator: Navigator){
...
Use the navigation host
Use the callback
Use onStartButtonPushed
declared on screen instantiation in the NavHost
on welcome screen buttons click
WelcomeScreen.kt (SourceSet: commonMain)
fun welcomeScreen(onStartButtonPushed: () -> Unit) {
...
Button(
modifier = Modifier.padding(all = 10.dp),
onClick = { onStartButtonPushed() }
) {
...
The same can be done for other screens
QuestionScreen.kt (commonMain)
fun questionScreen(questions: List<Question>, onFinishButtonPushed: (Int,Int) -> Unit) {
..
Button(
modifier = Modifier.padding(bottom = 20.dp),
onClick = {
/* FOR SPEAKER TALK DEMO ON WEB APP */
if (getPlatform().name == "WASM") {
onSaveStatQuestion(
questions[questionProgress].id,
questions[questionProgress].label,
selectedAnswer,
questions[questionProgress].correctAnswerId,
questions[questionProgress].answers[selectedAnswer.toInt() - 1].label
)
}
if (selectedAnswer == questions[questionProgress].correctAnswerId) {
score++
}
if (questionProgress < questions.size - 1) {
questionProgress++
selectedAnswer = 1
} else {
onFinishButtonPushed(score, questions.size)
}
}
}
...
ScoreScreen.kt (SourceSet : commonMain)
fun scoreScreen(score: Int,total:Int,onResetButtonPushed: () -> Unit){
...
Button(
modifier = Modifier.padding(all = 20.dp),
onClick = {
onResetButtonPushed()
}
)
...
🎯 Solutions
Sources
The full solution for this section is availabe here
✅ If everything is fine, congrats, you've just finish this codelab. You can now experiment your kotlin skills eveywhere !