androidkotlinandroid-jetpack-composecomposable

How to use @Preview with compose function that takes a param?


I have such an implementation:

...

    @Composable
    private fun PhoneVerificationCodeScreen(vm: MyViewModel) {
        Column(...) {
...
            OTPBlock(numberOfCells = NUMBER_OF_OTP_CELLS, isVerifyBtnEnabledState = vm.isVerifyBtnEnabledState)
...
        }
    }

...

There is my preview function:

    class MyViewModelProvider : PreviewParameterProvider<MyViewModel> {
        override val values: Sequence<MyViewModel> = sequenceOf(MyViewModel(
            SavedStateHandle()
        ))
    }

    @Preview(
        name = "Phone-portrait",
        device = Devices.PHONE,
        showBackground = true,
        backgroundColor = 0x111,
        showSystemUi = true
    )
    @Composable
    private fun PhonePreviewVerificationCodeScreen(
        @PreviewParameter(MyViewModelProvider::class) vm: MyViewModel
    ) = PhoneVerificationCodeScreen(vm = vm)

SPOILER: before I included ViewModel as a param it worked as expected.

I went through a few solutions in the google and the last one I tried was by using PreviewParameterProvider, however, it doesn't work as well.

So, the question is - how to "preview" the compose function that takes a param?

ERROR is:

java.lang.ClassNotFoundException: my_package.VerificationCodeViewModelProvider   at java.lang.ClassLoader.loadClass  at java.lang.ClassLoader.loadClass  at java.lang.Class.forName0  at java.lang.Class.forName  at androidx.compose.ui.tooling.ComposableInvoker.invokeComposable 


Solution

  • The method recommended on the Android developers site for creating previews of composables with ViewModels is to create an inner composable that accepts the ViewModel parameters as arguments:

    @Composable
    fun MyComposable(viewModel: MyViewModel) {
    
        val state by viewModel.state.collectAsStateWithLifecycle()
    
        MyComposable(
            state = state
        ) 
    }
    
    @Composable
    fun MyComposable(state: MyState) {
       ...
    }
    

    Then create a preview for the inner composable:

    @Preview
    @Composable
    fun MyComposablePreview(state: MyState = MyState()) {
        MyComposable(state = state)
    }
    

    See: https://developer.android.com/jetpack/compose/tooling/previews#preview-viewmodel

    There are various other methods as well, such as using an interface and creating a preview instance of the interface.