Search code examples
androidkotlinandroid-jetpack-composeandroid-jetpackandroid-jetpack-compose-preview

Can we or should use Preview compose function for main widget as well?


Like below are two functions

@Composable
private fun WaterCounter(modifier: Modifier = Modifier) {
    val count = 0
    Text(
        text = "You've had $count glasses of water",
        modifier = modifier.padding(all = 16.dp)
    )
}

@Preview(showBackground = true)
@Composable
private fun PreviewWaterCounter() {
    WaterCounter()
}

So, wouldn't it be better if we add @Preview annotation to the WaterCounter, which will save some lines of code and will work both as a preview and a widget?


Solution

  • For simple situations like your posted code, having a separate composable preview seems a bit too much, but consider this scenario with 2 composables with non-default parameters,

    @Composable
    fun PersonBiography(
        details: Data,
        otherParameters : Any?
    ) {
        Box(
            modifier = Modifier.background(Color.Red)
        ) {
            Text(details.dataValue)
        }
    }
    
    @Composable
    fun AccountDetails(
        details: Data
    ) {
        Box(
            modifier = Modifier.background(Color.Green)
        ) {
            Text(details.dataValue)
        } 
    }
    

    both of them requires same data class , the first one has an additional parameter. If I have to preview them I have to break their signature, assigning default values to them just for the sake of the preview.

    @Preview
    @Composable
    fun PersonBiography(
        details: Data = Data(dataValue = ""),
        otherParameters : Any? = null
    ) { … }
    
    @Preview
    @Composable
    fun AccountDetails(
        details: Data = Data(dataValue = "")
    ) { … }
    

    A good workaround on this is having 2 separate preview composables and taking advantage of PreviewParameterProvider to have a re-usable utility that can provide instances of the parameters I needed.

    class DetailsPreviewProvider : PreviewParameterProvider<Data> {
        override val values = listOf(Data(dataValue = "Some Data")).asSequence()
    }
    
    @Preview
    @Composable
    fun PersonBiographyPreview(@PreviewParameter(DetailsPreviewProvider::class) details: Data) {
        PersonBiography(
            details = details,
            // you may also consider creating a separate provider for this one if needed
            null
        )
    }
    
    @Preview
    @Composable
    fun AccountDetailsPreview(@PreviewParameter(DetailsPreviewProvider::class) details: Data) {
        AccountDetails(details)
    }
    

    enter image description here

    Or if PreviewParameterProvider is a bit too much, you can simply create a preview composable where you can create and supply the mock data.

    @Preview
    @Composable
    fun AccountDetailsPreview() {
        val data = Data("Some Account Information")
        AccountDetails(data)
    }
    

    enter image description here

    With any of these approaches, you don't need to break your actual composable's structure just to have a glimpse of what it would look like.