我正在尝试做什么:
我正在尝试在我的应用程序中实现 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 语句和其他不应该属于那里的东西。
如果我正确理解您的问题,您需要将 NavHostController 的实例传递到主屏幕。然后,在 MainScreen 中,观察 uiState.isCountrySelected。每当它变为 true 时,使用传递的 NavController 实例执行导航操作:
LaunchedEffect(key1 = uiState.isCountrySelected) {
if(uiState.isCountrySelected){
//navigate to your desired screen
}
}