Search code examples
androidkotlinandroid-jetpack-composeandroid-jetpack-navigationandroid-mvvm

Navigate using View Model in Jetpack Compose


Here is my MainActivity.kt file

Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
                    NavigationHoster()
                }

here is navhoster function

@Composable
fun NavigationHoster(){
    val navController = rememberNavController();
    
    NavHost(navController = navController, startDestination = "Home"){
        composable("Home"){ HomeScreen(navController = navController)}
        composable("Chat"){ ChatScreen()}
    }
}

here is HomeScreen Function

@OptIn(ExperimentalMaterial3Api::class)
//@Preview(showBackground = true, showSystemUi = true)
@Composable
fun HomeScreen(
    homeViewModel: HomeViewModel = viewModel(),
    navController: NavController
){
    val HomeViewState by homeViewModel.uiState.collectAsState()
    Scaffold (
        topBar = {
            TopAppBar(title = {
                Text(text = "Chat Wallet", style = MaterialTheme.typography.titleMedium)
            }, colors = TopAppBarDefaults.mediumTopAppBarColors(
                containerColor = MaterialTheme.colorScheme.primary,
                titleContentColor = MaterialTheme.colorScheme.background
            ))
        }
    ){
        paddingValues -> Box(modifier = Modifier.padding(paddingValues).fillMaxSize(), contentAlignment = Alignment.Center) {
            IconButton(onClick = { navController.navigate("Chat") }, colors = IconButtonDefaults.iconButtonColors(containerColor = MaterialTheme.colorScheme.primary)) {
                Icon(painter = painterResource(id = R.drawable.baseline_chat_24), contentDescription = null, tint = MaterialTheme.colorScheme.background)
            }

        }
    }
}

Here is my ViewModel

class HomeViewModel : ViewModel(){
    private var _uiState = MutableStateFlow(HomeData())
    var uiState : StateFlow<HomeData> = _uiState.asStateFlow()

    public fun ChangeName() {
        _uiState.value = HomeData(UserName = "hello there")
    }
}

These codes are works well and I tested. this viewmodel and screen file may be not linked.because I does different tests by changing it. can I know how to navigate to chat screen by calling changeName function from ui? I have no idea how to implement it

I didn't get any way to import navcontroller to viewmodel. so I stucked with that point. I thaught it have to import to viewmodel.

please give me simple example as well. thank you.


Solution

  • You best approach would be to add a variable to the viewModel called navigateToChatScreen and then when this variable is true you can navigate in your composable like this:

        class HomeViewModel : ViewModel(){
        private var _uiState = MutableStateFlow(HomeData())
        var uiState : StateFlow<HomeData> = _uiState.asStateFlow()
    
    private var _navigateToChatScreen = MutableStateFlow(false)
        var navigateToChatScreen : StateFlow<Boolean> = _navigateToChatScreen.asStateFlow()
    
        public fun ChangeName() {
            _uiState.value = HomeData(UserName = "hello there")
            _navigateToChatScreen.value = true
        }
    }
    

    Then you do it like this in your composable:

        @Composable
    fun HomeScreen(
        homeViewModel: HomeViewModel = viewModel(),
        navController: NavController
    ){
        val HomeViewState by homeViewModel.uiState.collectAsState()
    
        val navigateToChatScreen by homeViewModel.navigateToChatScreen.collectAsState()
    
    Launchedeffect(key= navigateToChatScreen){
      If(navigateToChatScreen){
         navController.navigate("chat")
      }
    }
        Scaffold (
            topBar = {
                TopAppBar(title = {
                    Text(text = "Chat Wallet", style = MaterialTheme.typography.titleMedium)
                }, colors = TopAppBarDefaults.mediumTopAppBarColors(
                    containerColor = MaterialTheme.colorScheme.primary,
                    titleContentColor = MaterialTheme.colorScheme.background
                ))
            }
        ){
            paddingValues -> Box(modifier = Modifier.padding(paddingValues).fillMaxSize(), contentAlignment = Alignment.Center) {
                IconButton(onClick = { homeViewModel.changeName()}, colors = IconButtonDefaults.iconButtonColors(containerColor = MaterialTheme.colorScheme.primary)) {
                    Icon(painter = painterResource(id = R.drawable.baseline_chat_24), contentDescription = null, tint = MaterialTheme.colorScheme.background)
                }
    
            }
        }
    }