Search code examples
androidkotlinandroid-jetpack-composeandroid-jetpack-navigationjetpack-compose-navigation

How to Navigate to mutliple Destinations from a Single Destination Using Jetpack Compose


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.


Solution

  • 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()
                }
            }
        }
    }