Compose 中的 ViewModel 和 UiState

问题描述 投票:0回答:1

我正在尝试做什么

我正在尝试在我的应用程序中实现 MVVM 模式。我试图在主屏幕的搜索栏中获取国家/地区字符串(例如“法国”)。我想使用这个字符串导航到特定的 CountryScreen(我需要国家/地区名称)。

我不明白什么 |我正在挣扎什么

我不知道怎么做,因为所有导航都应该在 NavGraph 中完成,所有逻辑都应该在 ViewModel 中完成。我检查搜索栏中写的单词是否有效,如果是,那么我想导航,但我无法从 ViewModel 导航(这是我搜索单词是否有效的地方 => 仅在这里我知道是否这个词是否有效),并且从 NavGraph 中我无法检查 viewModel 中的任何内容(我想导航到哪个国家/地区,如果该国家/地区存在等)

这更多是一个关于架构的问题,我确信有一种简单的方法可以做到这一点,但我不明白。这是

MainScreen
CountryScreen
NavGraph
MainScreenViewModel
MainScreenUiState
的代码:

MainScreen.kt

@Composable
fun MainScreen(
    onHomeClicked: () -> Unit,
    onStatisticsClicked: () -> Unit,
    onProfileClicked: () -> Unit,
    viewModel: MainScreenViewModel = viewModel()
) {
    val uiState = viewModel.uiState.collectAsState().value

    AppTheme {
        Column(modifier = Modifier.fillMaxSize()) {
            SearchAppBar(
                modifier = Modifier,
                searchBarQuery = uiState.searchBarQuery,
                onSearchClick = { viewModel.searchClick() },
                onQueryChange = { viewModel.updateSearchBarQuery(it) },
                isSearchBarActive = uiState.isSearchBarActive,
                onActiveChange = {}
            )
            FilterButtons(modifier = Modifier)
            Spacer(modifier = Modifier.weight(1f))
            CustomNavigationBar(
                modifier = Modifier,
                isHomeSelected = uiState.isHomeSelected,
                isStatisticsSelected = uiState.isStatisticsSelected,
                isProfileSelected = uiState.isProfileSelected,
                onHomeClicked = onHomeClicked,
                onStatisticsClicked = onStatisticsClicked,
                onProfileClicked = onProfileClicked
            )
        }
    }
}

CountryScreen.kt

@Composable
fun CountryScreen(
    modifier: Modifier = Modifier,
    goBackOnClick: () -> Unit,
    goHomeOnClick: () -> Unit,
    countryName: String,
    visitors: Int
) {
    LazyColumn(modifier = modifier) {
        item { GoBackTopAppBar(goBackOnClick = goBackOnClick, goHomeOnClick = goHomeOnClick) }
        item { CountryInformationSection(countryName = countryName, visitors = visitors) }
        items(DataSources.types) { type ->
            AttractionTypeSection(modifier = Modifier, type)
        }
    }
}

NavHost.kt

@Composable
fun TrailQuestNavHost(
    navController: NavHostController,
    modifier: Modifier = Modifier,
) {
    NavHost(
        navController = navController,
        startDestination = MainScreenClass,
        modifier = modifier
    ) {
        composable<MainScreenClass> {
            MainScreen(
                viewModel = viewModel(),
                onHomeClicked = { },
                onStatisticsClicked = {
                    navController.navigate(
                        UserProfileScreenClass(
                            userName = "HogRidaa",
                            attractionsCompleted = 40f,
                            attractionTotal = 123f,
                            userTitle = "Adventurer",
                            userLevel = 6,
                            bioText = "I don't know",
                            mostLikedCountries = listOf("Albania", "France", "Belgium"),
                            mostLikedActivities = listOf("Zoo", "Nature", "Food")
                        )
                    )
                },
                onProfileClicked = {}
            )
        }
    }
}

MainScreenUiState.kt

data class MainScreenUiState(
    val isCountrySelected: Boolean = false,
    val isSearchBarActive: Boolean = false,
    val isHomeSelected: Boolean = false,
    val isStatisticsSelected: Boolean = false,
    val isProfileSelected: Boolean = false,
    val searchBarQuery: String = ""
)

MainScreenViewModel.kt

class MainScreenViewModel : ViewModel() {
    var uiState = MutableStateFlow(MainScreenUiState())
        private set

    init {
        //Database
        uiState.value = MainScreenUiState()
    }


    fun updateSearchBarQuery(newQuery: String) {
        uiState.update {
            it.copy(
                searchBarQuery = newQuery
            )
        }
    }

    fun searchClick() {
        if (this.uiState.value.searchBarQuery in DataSources.countries) {
            // navigate to CountryScreen
            uiState.update {
                it.copy(
                    isCountrySelected = true
                )
            }
        } else {
            updateSearchBarQuery("This country does not exist")
        }
    }

    fun resetSearchBarQuery() {
        updateSearchBarQuery("")
    }
}

我在尝试什么

我试图以某种方式使用

isCountrySelected
MainScreen.kt
知道我要导航到哪个国家,但这一切感觉非常糟糕,因为所有逻辑都应该在 viewModel 中,而我只是将屏幕可组合项弄乱if 语句和其他不应该属于那里的东西。

kotlin mvvm android-jetpack-compose
1个回答
0
投票

如果我正确理解您的问题,您需要将 NavHostController 的实例传递到主屏幕。然后,在 MainScreen 中,观察 uiState.isCountrySelected。每当它变为 true 时,使用传递的 NavController 实例执行导航操作:

LaunchedEffect(key1 = uiState.isCountrySelected) {
        if(uiState.isCountrySelected){
            //navigate to your desired screen
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.