簡體   English   中英

具有 ViewModel 參數時,Jetpack Compose 預覽未顯示

[英]Jetpack Compose Preview is not showing when having a ViewModel parameter

我正在使用 Jetpack Compose 並注意到未顯示預覽。 我讀過這樣的文章,但我的問題似乎有不同的根本原因。 甚至我在 compose function 中為所有參數添加了默認值,如下所示:

@OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
@ExperimentalFoundationApi
@Preview
fun VolumeSettingsScreen(
    speech: SpeechHelper = SpeechHelper(), // my class that converts text to speech
    viewModel: VolumeSettingsViewModel = hiltViewModel(), // using Hilt to inject ViewModels
    navController: NavHostController = rememberNavController() // Compose Navigation component
) {
    MyAppheme {
        Box(
             ...
        )
    }
}

當我回滾一些更改時,我意識到@Preview不支持viewModels ,無論它們是否注入了 Hilt。

知道如何解決這個問題嗎?

我設法通過將 ViewModel 的函數包裝到數據類中來可視化屏幕預覽,如下所示:

@OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
@ExperimentalFoundationApi
@Preview
fun VolumeSettingsScreen(
    modifier: Modifier = Modifier,
    speechCallbacks: SpeechCallbacks = SpeechCallbacks(),
    navigationCallbacks: NavigationCallbacks = NavigationCallbacks(),
    viewModelCallbacks: VolumeSettingsScreenCallbacks = VolumeSettingsScreenCallbacks()
) {
    MyAppheme {
        Box(
             ...
        )
    }
}

我沒有直接在 compose 中傳遞 ViewModel,而是需要數據 class 中的函數,例如,如下所示:

data class VolumeSettingsScreenCallbacks(
    val uiState: Flow<BaseUiState?> = flowOf(null),
    val onValueUpSelected: () -> Boolean = { false },
    val onValueDownSelected: () -> Boolean = { false },
    val doOnBoarding: (String) -> Unit = {},
    val onScreenCloseRequest: (String) -> Unit = {} 
)

我創建了一個在 ViewModel 中生成這些回調的方法,如下所示:

@HiltViewModel
class VolumeSettingsViewModel @Inject constructor() : BaseViewModel() {

    fun createViewModelCallbacks(): VolumeSettingsScreenCallbacks =
        VolumeSettingsScreenCallbacks(
            uiState = uiState,
            onValueUpSelected = ::onValueUpSelected,
            onValueDownSelected = ::onValueDownSelected,
            doOnBoarding = ::doOnBoarding,
            onScreenCloseRequest = ::onScreenCloseRequest
        )

 ....
}

在 NavHost 中,我像這樣提升了 ViewModel 的創建:

    @Composable
    @ExperimentalFoundationApi
    fun MyAppNavHost(
        speech: SpeechHelper,
        navController: NavHostController,
        startDestination: String = HOME.route,
    ): Unit = NavHost(
        navController = navController,
        startDestination = startDestination,
    ) {
        ...
    
        composable(route = Destination.VOLUME_SETTINGS.route) {
            hiltViewModel<VolumeSettingsViewModel>().run {
                VolumeSettingsScreen(
                    modifier = keyEventModifier,
                    speechCallbacks = speech.createCallback() // my function,
                    navigation callbacks = navController.createCallbacks(), //it is mine extension function                  
                    viewModelCallbacks = createViewModelCallbacks()
                )
            }
        }
    
        ...
    }

它有點復雜,但它有效:D。 如果有一些彗星需要改進,我會很高興。

你有沒有考慮過有一個結構,你有一個Screen和實際的Content這樣分開?

// data class
data class AccountData(val accountInfo: Any?)

// composable "Screen", where you define contexts, viewModels, hoisted states, etc
@Composable
fun AccountScreen(viewModel: AccountViewModel = hiltViewModel()) {

    val accountData = viewModel.accountDataState.collectAsState()

    AccountContent(accountData = accountData) {
        // click callback
    }
}

//your actual composable that hosts your child composable widget/components
@Composable
fun AccountContent(
    accountData: AccountData,
    clickCallback: () ->
) {
   ...
}

在哪里可以預覽這樣的Content

@Preview
@Composable
fun AccountContentPreview() {

    // create some mock AccountData
    val mockData = AccountData(…)
    AccountContent(accountData = mockData) {
         // I'm not expecting some actual ViewModel calls here, instead I'll just manipulate the mock data
    }
}

這樣,實際可組合內容不需要配置的所有組件都被分開,讓您從配置預覽的麻煩中解脫出來。

只是一個補充說明,可能是題外話,我只是注意到你有一個這樣的參數,

speech: SpeechHelper = SpeechHelper()

您可能會考慮使用compositionLocalProvider (如果需要),它可以清理您的參數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM