如何根据两个值从 ViewModel UIState 更新 Jetpack Compose 中的 UI?

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

我对以下场景有点困惑:

  1. 最初我在屏幕上显示 DatePicker 模式。

  2. 当用户选择日期时,我会显示几个按钮。

  3. 当用户单击任何这些按钮时,我想将两条数据传递给 ViewModel:所选日期和按下的按钮类型,以使用这两个数据在存储库中搜索数据标准。

我的问题是,在包含 ViewModel 之前,我找不到传递这两条数据的方法。

我正在尝试在 Now In Android 中做类似

InterestsScreen 的事情。

我在另一个场景中有一个类似的代码,它可以工作,但是日期是从系统中获取的,所以没有问题。这里的日期必须由用户从 DatePicker 给出。

我没有显示用例或存储库的代码,当我向其传递正确的参数时,该代码可以正常工作。我的问题是,当我有选定的日期和用户按下的按钮类型时,我不知道如何调用 ViewModel。

我展示了我的代码的相关部分:

NavGraphBuilder

composable<CalendarRoute> {
    CalendarScreen(onTopicClick = onTopicClick,onDateSelected={})

CalendarScreen
(从 NavGraphBuilder 调用)

@Composable
fun CalendarScreen(
    onTopicClick: (String) -> Unit,
    onDateSelected: (Long?) -> Unit,
    viewModel: CalendarViewModel = hiltViewModel()
) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    DatePickerAndButtons(
        onTopicClick = viewModel::onTopicClick,
        onDateSelected = viewModel::onDateSelected,
        uiState = uiState
    )
}

DatePickerAndButtons

@ExperimentalLayoutApi
@Composable
fun DatePickerAndButtons(
    onTopicClick: (String) -> Unit,
    onDateSelected: (Long?) -> Unit,
    uiState: CalendarUiState
) {
    var showTopics by remember { mutableStateOf(false) }
    var showDatePicker by remember { mutableStateOf(true) }
    var selectedDate by remember { mutableStateOf<Long?>(null) }

    when (uiState) {
        CalendarUiState.Empty -> Text("Empty")
        CalendarUiState.Error -> Text("Error")
        CalendarUiState.Loading -> {
            Text("Loading")
            //showDatePicker=true
        }
        is CalendarUiState.CalendarData -> {
            showTopics=false
            //showDatePicker=false
            if(uiState.topics.isNotEmpty()) {
                //Show data
            }else{
                //¿?
            }
        }
    }

    if (selectedDate != null) {
        val date = Date(selectedDate!!)
        val formattedDate = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()).format(date)
        Text("Selected date: $formattedDate")
    } else {
        Text("No date selected")
    }
    if (showDatePicker) {
        DatePickerModal(
            onDateSelected = {
                selectedDate = it
                onDateSelected(it)
                //viewModel.onDateSelected(selectedDate)
                showDatePicker = false
                showTopics=true
            },
            onDismiss = { showDatePicker = false }
        )
    }

    if(showTopics) {
        //Code that create buttons to be clicked
    }

}

ViewModel

@HiltViewModel
class CalendarViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
    val userDataRepository: UserDataRepository,
    val universalisRepository: UniversalisRepository,
    getTopicWithDate: GetUniversalisFromCalendarUseCase,
) : ViewModel() {
    private val selectedTopicIdKey = "selectedTopicIdKey"
    private val selectedDateKey = "selectedDateKey"
    private val calendarRoute: CalendarRoute = savedStateHandle.toRoute()
    private val selectedTopicId = savedStateHandle.getStateFlow(
        key = selectedTopicIdKey,
        initialValue = "1" //calendarRoute.topicId,
    )
    private val selectedDate = savedStateHandle.getStateFlow(
        key = selectedDateKey,
        initialValue = 0
    )
    
    val uiState: StateFlow<CalendarUiState> = combine(
        selectedTopicId,
        getTopicWithDate.invoke(
            date = selectedDate.value,
            title = "TODO:Title",
            selectedTopicId = selectedTopicId.value
        ),
        CalendarUiState::CalendarData,
    ).
    stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5_000),
        initialValue = CalendarUiState.Loading,
    )


    fun onTopicClick(topicId: String?) {
        savedStateHandle[selectedTopicIdKey] = topicId
    }

    fun onDateSelected(date: Long?) {
        savedStateHandle[selectedDateKey] = date
    }
    
}
android android-jetpack-compose android-viewmodel
1个回答
0
投票

您错误地组合了两个不同的流程阶段。

topicId
date
是Topic的查询参数,所以只有当它们改变时才会开始查询。
所以你的主题查询结果将是这样的:

    private val topics: Flow<YourTopicsModel> = combine(
        selectedDate,
        selectedTopicId,
    ){date,topicId->
        date to topicId
    }.flatMapLatest {
        getTopicWithDate(
            date = it.first,  
            title = "TODO:Title",
            selectedTopicId = it.second
        )
    }

那么你的

uiState
将是:

    val uiState: StateFlow<CalendarUiState> = combine(
        selectedTopicId,
        topics,
        CalendarUiState::CalendarData,
    ).
    stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5_000),
        initialValue = CalendarUiState.Loading,
    )
© www.soinside.com 2019 - 2024. All rights reserved.