⭐ Contribute!
⭐ Contribute!
  • Home
  • 🚀 Let's start
  • Configure KMP
  • User interface
  • Navigation
  • Ressources
  • Architecture
  • Connectivity
  • Preferences
  • (Local Database)

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)
...
            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.

routes overview

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 QuizScreento the ScoreScreen
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)
                    }
                )
            }
        }
    }
}

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 !

📖 Further reading

  • Precompose navigation
  • Moko
  • KMP awesome libs database
  • Animation in compose cheat sheet
  • The accompagnist : a group of libraries that aim to supplement Compose
  • AAkira libs database
Edit this page
Last Updated:
Contributors: Brah, Ibrahim Gharbi, A187839
Prev
User interface
Next
Ressources