Home > Software engineering >  How to Navigate to mutliple Destinations from a Single Destination Using Jetpack Compose
How to Navigate to mutliple Destinations from a Single Destination Using Jetpack Compose

Time:11-19

In summary I want to navigate to a destination depending on which item is clicked.

enter image description here

But the problem is the way I created these items, which is in a way I don't how to isolate item, and give them an onClick function, Singularly.

PS. I used a data class and object function, to make the items;

data class MenuData(
    Val id: Int,
    Val title: String,
    val menuImageId: Int = 0
)
object MenuModel {

    .....

    fun menuModelList(context: Context) = listOf(

        MenuData(
            id = 1,
            title = context.getString(R.string.menu_log),
            description = context.getString(R.string.menu_logText),
            menuImageId = R.drawable.menu_log
        ),
      .....
    )
}


Usually what I do to navigate is (Sample Code):

@Composable
fun WaysCard(
    waysInfo: WaysData,
    onWaysCardClick: (Int) -> Unit,
    modifier: Modifier = Modifier
) {
    Surface(
        shape = MaterialTheme.shapes.small,
        elevation = 10.dp,
        modifier = modifier
            .clickable { onWaysCardClick(waysInfo.id) }
    ) 
    ....
}

As you can see I gave the composable a click function and pass the data class as parameter, because usually the items are generic, most of their content are arranged in a similar manner. But in this one I'm trying to do now. The contents are not similar in anyway.. So I made Destinations of each of items. So I want to navigate to these predefined destinations, from the MenuScreen.Kt.

I don't know what to pass to the onClick function to navigate to these destinations. or if I should even write it the same way I used to.

Here's the code (MenuScreen.Kt):

@Composable
fun MenuCard(
    menuInfo: MenuData,
    onMenuCardClick: (Int) -> Unit,
    modifier: Modifier = Modifier
) {
    Surface(
        shape = MaterialTheme.shapes.small,
        elevation = 4.dp,
        modifier = modifier
            .clickable {  }
    ) {
        ....
    }
}

Please for understanding purpose, let's call the predefined destinations; LogScreen.kt, ToDoScreen.kt, LessonsScreen.kt and ContactScreen.kt.

I don't know if you need more information, please if you do, I'm more than happy to provide them.

I sinerely will be grateful for any help provided.. Thanks to you in advance.

CodePudding user response:

If I understand the questions correctly, I have a solution for you, I don't know how much it will work for you

But if you don't understand something, please ask, I will gladly guide you

Please do what I say and see the output. If it matches what you want, let me know by leaving a comment and I will give you a full explanation

1 - Create a Kotlin file with the name you want - I named it Navigation

2 - Put all the codes that I have included in the attachment in that file


import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.navigation
import androidx.navigation.compose.rememberNavController

sealed class Screen(val route: String) {
    object Menu : Screen("menu")
}

sealed class LeafScreen(
    private val route: String
) {
    fun createRoute(root: Screen) = "${root.route}/$route"

    object Menu : LeafScreen("menu")
    object Lessons : LeafScreen("lessons")
    object Log : LeafScreen("log")
    object ToDo : LeafScreen("todo")
    object Contact : LeafScreen("contact")
}


@Composable
fun AppNavigation() {
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = Screen.Menu.route
    ) {
        navigation(
            route = Screen.Menu.route,
            startDestination = LeafScreen.Menu.createRoute(Screen.Menu)
        ) {
            composable(
                LeafScreen.Menu.createRoute(Screen.Menu)
            ) {
                MenuScreen(
                    navigateToScreen = {
                        when (it) {
                            1 -> navController.navigate(LeafScreen.Log.createRoute(Screen.Menu))
                            2 -> navController.navigate(LeafScreen.Lessons.createRoute(Screen.Menu))
                            3 -> navController.navigate(LeafScreen.Contact.createRoute(Screen.Menu))
                            4 -> navController.navigate(LeafScreen.ToDo.createRoute(Screen.Menu))
                        }
                    }
                )
            }
            composable(
                LeafScreen.Lessons.createRoute(Screen.Menu)
            ) {
                LessonsScreen()
            }
            composable(
                LeafScreen.Log.createRoute(Screen.Menu)
            ) {
                LogScreen()
            }
            composable(
                LeafScreen.ToDo.createRoute(Screen.Menu)
            ) {
                ToDoScreen()
            }
            composable(
                LeafScreen.Contact.createRoute(Screen.Menu)
            ) {
                ContactScreen()
            }
        }
    }
}

@Composable
fun ContactScreen() {
    Box(Modifier.fillMaxSize()) {
        Text(text = "ContactScreen", modifier = Modifier.align(Alignment.Center))
    }
}

@Composable
fun ToDoScreen() {
    Box(Modifier.fillMaxSize()) {
        Text(text = "ToDoScreen", modifier = Modifier.align(Alignment.Center))
    }
}

@Composable
fun LogScreen() {
    Box(Modifier.fillMaxSize()) {
        Text(text = "LogScreen", modifier = Modifier.align(Alignment.Center))
    }
}

@Composable
fun LessonsScreen() {
    Box(Modifier.fillMaxSize()) {
        Text(text = "LessonsScreen", modifier = Modifier.align(Alignment.Center))
    }
}

data class MenuData(
    val id: Int,
    val title: String,
    val menuImageId: Int = 0
)

data class MenuViewState(
    val menus: List<MenuData> = arrayListOf<MenuData>().apply {
        add(MenuData(id = 1, title = "log", 0))
        add(MenuData(id = 2, title = "lessons", 0))
        add(MenuData(id = 3, title = "contacts", 0))
        add(MenuData(id = 4, title = "todo", 0))
    }
)

@Composable
fun MenuScreen(
    navigateToScreen: (Int) -> Unit
) {
    val uiState by remember {
        mutableStateOf(MenuViewState())
    }
    LazyColumn(

3 - And finally, put Composable Navigation in your MainActivity.kt

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import stackoverflow.answers.ui.theme.StackOverflowAnswersTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            StackOverflowAnswersTheme {
                AppNavigation()
            }
        }
    }
}
  • Related