提问人:NewPartizal 提问时间:10/26/2023 更新时间:10/28/2023 访问量:47
如何在 jetpack compose 中将一个视图模型用于两个可组合屏幕?
How can I use one viewmodel for two composable screen in jetpack compose?
问:
我有一个名为AddNutritionSearchRoute的屏幕,在这个屏幕上有用户选择的食物,例如苹果、梨、西瓜等。此屏幕上有一个列表按钮。当用户按下列表按钮时,他会转到屏幕以列出名为 SelectedItemListRoute 的选定项目,用户可以在此处删除他选择的项目,例如苹果、梨、西瓜列表。让它删除苹果并返回 AddNutritionSearchRoute 屏幕。再次说到这个屏幕,我需要使用相同的列表,即梨和西瓜必须保留在列表中,因为苹果已被删除。不断移动列表似乎很荒谬,一定有一种更简单的方法。我的代码如下
AddNutritionSearchRoute
@Composable
fun AddNutritionSearchRoute(
navHostController: NavHostController,
mealId:Int?,
viewModel: AddNutritionSearchViewModel = hiltViewModel()
...
AddNutritionSearchViewModel 视图模型
@HiltViewModel
class AddNutritionSearchViewModel @Inject constructor(
...
) : ViewModel() {
private val _selectedNtrItem = MutableStateFlow(SelectedNtrItem())
val selectedNtrItem: StateFlow<SelectedNtrItem> = _selectedNtrItem.asStateFlow()
fun deleteItemFromList(item: NutritionSearchItem) {
_selectedNtrItem.value.items.remove(item)
}
fun addSelectedNutritionItem(
ntrItem: NutritionSearchItem,
selectedNtrItem: ArrayList<NutritionSearchItem>
) {
if (selectedNtrItem.contains(ntrItem)) {
selectedNtrItem.remove(ntrItem)
} else {
selectedNtrItem.add(ntrItem)
}
}
...
SelectedItemList屏幕
如果我以这种方式定义如下所示的视图模型,并通过视图模型访问列表,则列表将显示为空。即使我选择了一个元素,列表也可能是空的,因为我再次定义了视图模型。
@Composable
fun SelectedItemListRoute(
navHostController: NavHostController,
list: SelectedNtrItem?
viewModel: AddNutritionSearchViewModel = hiltViewModel(),
) {
SelectedItemListScreen(navHostController,list?.items ?: arrayListOf() )
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun SelectedItemListScreen(
navHostController: NavHostController,
list: ArrayList<NutritionSearchItem>
) {
val scope = rememberCoroutineScope()
val modalBottomSheetState =
rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
ModalBottomSheetLayout(
sheetContent = {
BaseBottomSheet(
content = {
DeleteItemConfirmation(
onConfirmClick = {
scope.launch {
modalBottomSheetState.hide()
}
},
onCancelClick = {
scope.launch {
modalBottomSheetState.hide()
}
}
)
}
)
},
sheetState = modalBottomSheetState,
sheetShape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
) {
Scaffold(topBar = {
SelectedItemListTopBar(
onClickCancel = {
navHostController.popBackStack()
},
listSize = list.size
)
}) { padding ->
LazyColumn(modifier = Modifier.padding(15.dp)) {
items(list) { item ->
BaseNtrItem(
ntrId = item.nutritionId,
image = item.image,
ntrName = item.nutritionName,
kcal = item.kcal,
unit = item.unitName,
onClick = {}
) {
Row() {
Image(
modifier = Modifier.clickable {
scope.launch {
modalBottomSheetState.animateTo(ModalBottomSheetValue.Expanded)
}
},
painter = painterResource(id = R.drawable.ic_red_delete),
contentDescription = ""
)
}
}
}
}
}
}
}
导航:
...
composable(
route = "${ContentWidgetScreens.SelectedItemListScreen.route}/{$SELECTED_NTR_ITEM_LIST}",
arguments = listOf(
navArgument(SELECTED_NTR_ITEM_LIST) {
type = ANSAssetParamType()
}
)
) {backStackEntry ->
val selectedNtrItemList = backStackEntry.arguments?.getParcelable<SelectedNtrItem>(SELECTED_NTR_ITEM_LIST)
SelectedItemListRoute(navHostController,selectedNtrItemList)
}
composable(
route = "${ContentWidgetScreens.AddNutritionSearchScreen.route}?$MEAL_ID={$MEAL_ID}",
arguments = listOf(
navArgument(name = MEAL_ID) {
type = NavType.IntType
defaultValue = -1
})
)
{ backStackEntry ->
val mealId = backStackEntry.arguments?.getInt(MEAL_ID)
AddNutritionSearchRoute(navHostController,mealId)
}
...
答:
0赞
WBarber
10/28/2023
#1
因此,您可以在导航中执行此操作,例如NavHost。只需将 ViewModel 传递给 NavHost,然后从 NavHost 向下传递到您希望访问它的屏幕即可。这样,两个屏幕都可以访问同一个 ViewModel 实例
fun NavHostExample(
navController: NavHostController,
sharedViewModel: MySharedViewModel
) {
NavHost(navController) {
composable( route = Screens.MainMenuScreen.route ) {
MainScreen(
navController = navController,
viewModel = sharedViewModel // passing the ViewModel to first screen
)
}
composable( route = Screens.Settings.route ) {
SettingsScreen(
navController = navController,
viewModel = sharedViewModel // passing same ViewModel instance to second screen
)
}
}
}
只需初始化您的 ViewModel 并将其传递给您的 NavHost,无论您在哪里:
// Initialise
val sharedViewModel = MySharedViewModel()
// Pass to nav controller, and we have it setup to pass to views
NavHostExample(
navController = navController,
sharedViewModel = sharedViewModel
)
这样,我们就不会通过导航传递复杂的数据,而是指向 SharedViewModel 的指针,两个屏幕现在都可以访问该指针,使 SharedViewModel 成为我们的 DataLayer
评论