Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Practical Tips and Tricks to Improve Your Compo...

Practical Tips and Tricks to Improve Your Compose Previews (DevFest Venezia 2024)

Jetpack Compose Preview is a powerful tool that provides real-time feedback on how our composables are rendered and even on how they behave and animate in certain conditions. While writing useful previews seems like a straightforward task, there are some things that we need to keep in mind. Preview code won't reach users of your app (hopefully!); however, it's more likely that the author of the preview and future peers as well might have to work with them eventually.

This talk will touch on the following topics:
- Recap on the main features and limitations of Compose previews
- How we can overcome the limitations of @Preview being an annotation
- How we can make our previews developer-friendly
- What we can use our previews for besides checking how our composables are rendered and how they behave

István Juhos

November 16, 2024
Tweet

More Decks by István Juhos

Other Decks in Programming

Transcript

  1. @Preview(device = "spec:width=960dp,height=1080dp,dpi=480") @Composable private fun TitleSlidePreview() { PreviewBox {

    TitleSlide() } } @Composable private fun TitleSlide() { Column( modifier = Modifier .fillMaxSize() .paint( painter = painterResource( id = R.drawable.glenn_carstens_peters, ), contentScale = ContentScale.FillBounds, ) .padding(32.dp) ) { Title( modifier = Modifier .fillMaxWidth() .padding(top = 32.dp), fontSize = 70.sp, ) Column( horizontalAlignment = CenterHorizontally, modifier = Modifier .fillMaxWidth() ) { Name( modifier = Modifier .weight(1f) .padding(bottom = 66.dp), imageHeight = 66.dp, textSize = 70.sp, ) Contacts( modifier = Modifier .padding( bottom = 16.dp, end = 16.dp, ), fontSize = 50.sp, ) } } } Practical Tips and Tricks to Improve Your Compose Previews István Juhos @istvanjuhos.dev
  2. #DevFestVenezia @istvanjuhos.dev @Preview @Composable private fun ListItemPreview() { AppTheme {

    ListItem( text = "List item", onClick = {}, ) } } Compose preview
  3. #DevFestVenezia @istvanjuhos.dev @Preview @Composable private fun ListItemPreview() { AppTheme {

    ListItem( text = "List item", onClick = {}, ) } } Compose preview
  4. #DevFestVenezia @istvanjuhos.dev @Preview @Composable private fun ListItemPreview() { AppTheme {

    ListItem( text = "List item", onClick = {}, ) } } • Code Compose preview
  5. #DevFestVenezia @istvanjuhos.dev • Code, that • will never reach production

    @Preview @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } Compose preview
  6. #DevFestVenezia @istvanjuhos.dev • Code, that • will never reach productio

    n​ … 🤞 @Preview @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } Compose preview
  7. #DevFestVenezia @istvanjuhos.dev • Code, that • will never reach production…

    • others will read 🤞 @Preview @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } Compose preview
  8. #DevFestVenezia @istvanjuhos.dev • Code, that • will never reach production…

    • others will read • needs to be maintained 🤞 @Preview @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } Compose preview
  9. #DevFestVenezia @istvanjuhos.dev • Code, that • will never reach production…

    • others will read • needs to be maintained • might be duplicated 🤞 @Preview @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } Compose preview
  10. #DevFestVenezia @istvanjuhos.dev • Code, that • will never reach production…

    • others will read • needs to be maintained • might be duplicated • might be used for other purposes 🤞 @Preview @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } Compose preview
  11. #DevFestVenezia @istvanjuhos.dev Consider IDE themes @Composable fun ListItem( text: String,

    onClick: () -> Unit, modifier: Modifier = Modifier, ) { Row( verticalAlignment = Alignment.CenterVertically, modifier = modifier .clickable(onClick = onClick) .padding(16.dp), ) { Text( text = text, style = PreviewTheme.typography.bodyMedium, color = PreviewTheme.colors.text, modifier = Modifier.weight(1f), ) Image( imageVector = KeyboardArrowRight, contentDescription = null, colorFilter = ColorFilter.tint(PreviewTheme.colors.text) ) } }
  12. Consider IDE themes • Render Composable functions annotated with @Preview

    @Composable fun ListItem( text: String, onClick: () -> Unit, modifier: Modifier = Modifier, ) { Row( verticalAlignment = Alignment.CenterVertically, modifier = modifier .clickable(onClick = onClick) .padding(16.dp), ) { Text( text = text, style = PreviewTheme.typography.bodyMedium, color = PreviewTheme.colors.text, modifier = Modifier.weight(1f), ) Image( imageVector = KeyboardArrowRight, contentDescription = null, colorFilter = ColorFilter.tint(PreviewTheme.colors.text) ) } }
  13. Consider IDE themes • Render Composable functions annotated with @Preview

    @Composable fun ListItem( text: String, onClick: () -> Unit, modifier: Modifier = Modifier, ) { Row( verticalAlignment = Alignment.CenterVertically, modifier = modifier .clickable(onClick = onClick) .padding(16.dp), ) { Text( text = text, style = PreviewTheme.typography.bodyMedium, color = PreviewTheme.colors.text,
  14. Consider IDE themes • Render Composable functions annotated with @Preview

    @Composable fun ListItem( text: String, onClick: () -> Unit, modifier: Modifier = Modifier, ) { Row( verticalAlignment = Alignment.CenterVertically, modifier = modifier .clickable(onClick = onClick) .padding(16.dp), ) { Text( text = text, style = PreviewTheme.typography.bodyMedium, color = PreviewTheme.colors.text,
  15. #DevFestVenezia @istvanjuhos.dev @Preview @Composable private fun ListItemPreview() { AppTheme {

    ListItem( text = "List item", onClick = {}, ) } } Consider IDE themes
  16. #DevFestVenezia @istvanjuhos.dev @Preview @Composable private fun ListItemPreview() { AppTheme {

    ListItem( text = "List item", onClick = {}, ) } } Consider IDE themes
  17. #DevFestVenezia @istvanjuhos.dev @Preview @Composable private fun ListItemPreview() { AppTheme {

    ListItem( text = "List item", onClick = {}, ) } } Consider IDE themes
  18. #DevFestVenezia @istvanjuhos.dev @Preview( showBackground = true, ) @Composable private fun

    ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } Consider IDE themes
  19. #DevFestVenezia @istvanjuhos.dev @Preview( showBackground = true, ) @Composable private fun

    ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } Consider IDE themes vs
  20. #DevFestVenezia @istvanjuhos.dev @Preview( showBackground = true, ) @Composable private fun

    ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } Use annotation parameters
  21. #DevFestVenezia @istvanjuhos.dev @Preview( showBackground = true, ) @Composable private fun

    ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } Use annotation parameters
  22. #DevFestVenezia @istvanjuhos.dev @Preview( showBackground = true, backgroundColor = 0xFF_E7ECF4, )

    @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } Use annotation parameters
  23. #DevFestVenezia @istvanjuhos.dev @Preview( showBackground = true, backgroundColor = 0xFF_E7ECF4, //

    gray.w500 ) @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } Use annotation parameters
  24. #DevFestVenezia @istvanjuhos.dev Use annotation parameters @Preview( showBackground = true, backgroundColor

    = GRAY_W500, ) @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } } const val GRAY_W500 = 0xFF_E7ECF4 ...
  25. #DevFestVenezia @istvanjuhos.dev Use annotation parameters @Preview( showBackground = true, backgroundColor

    = GRAY_W500, ) @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } }
  26. #DevFestVenezia @istvanjuhos.dev Use annotation parameters @Preview( showBackground = true, backgroundColor

    = GRAY_W500, uiMode = Configuration.UI_MODE_NIGHT_YES, ) @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } }
  27. #DevFestVenezia @istvanjuhos.dev Use annotation parameters @Preview( showBackground = true, backgroundColor

    = GRAY_W500, ) @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, ) } }
  28. #DevFestVenezia @istvanjuhos.dev Use annotation parameters @Preview( showBackground = true, backgroundColor

    = GRAY_W500, ) @Preview( showBackground = true, backgroundColor = GRAY_W500, ) @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, )
  29. #DevFestVenezia @istvanjuhos.dev Use annotation parameters @Preview( showBackground = true, backgroundColor

    = GRAY_W500, ) @Preview( showBackground = true, backgroundColor = DARK_GRAY_W500, ) @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {}, )
  30. #DevFestVenezia @istvanjuhos.dev Use annotation parameters @Preview( showBackground = true, backgroundColor

    = GRAY_W500, ) @Preview( showBackground = true, backgroundColor = DARK_GRAY_W500, uiMode = Configuration.UI_MODE_NIGHT_YES, ) @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {},
  31. #DevFestVenezia @istvanjuhos.dev Use annotation parameters @Preview( showBackground = true, backgroundColor

    = GRAY_W500, ) @Preview( showBackground = true, backgroundColor = DARK_GRAY_W500, uiMode = Configuration.UI_MODE_NIGHT_YES, ) @Composable private fun ListItemPreview() { AppTheme { ListItem( text = "List item", onClick = {},
  32. #DevFestVenezia @istvanjuhos.dev @Preview( name = "Light - Primary", group =

    "Light/Dark - Primary", showBackground = true, backgroundColor = GRAY_W500, ) @Preview( name = "Dark - Primary", group = "Light/Dark - Primary”, showBackground = true, backgroundColor = DARK_GRAY_W500, uiMode = UI_MODE_NIGHT_YES, ) @Composable private fun ListItemPreview() { ... } Group your previews
  33. #DevFestVenezia @istvanjuhos.dev @Preview( name = "Light - Secondary", group =

    "Light/Dark - Secondary", showBackground = true, backgroundColor = GRAY_W100, ) @Preview( name = "Dark - Secondary", group = "Light/Dark - Secondary", showBackground = true, backgroundColor = DARK_GRAY_W100, uiMode = UI_MODE_NIGHT_YES, ) @Composable private fun ListItemPreview() { ... } Group your previews
  34. #DevFestVenezia @istvanjuhos.dev @Preview( ... ) @Preview( ... ) @Preview( ...

    ) @Preview( ... ) @Composable private fun ListItemPreview() { ... } Group your previews
  35. #DevFestVenezia @istvanjuhos.dev @Preview( ... ) @Preview( ... ) @Preview( ...

    ) @Preview( ... ) @Composable private fun ListItemPreview() { ... } Group your previews
  36. #DevFestVenezia @istvanjuhos.dev @Preview( ... ) @Preview( ... ) @Preview( ...

    ) @Preview( ... ) @Composable private fun ListItemPreview() { ... } Create multipreviews
  37. @Preview( name = "Light - Primary", group = "Light/Dark -

    Primary", showBackground = true, backgroundColor = GRAY_W500, ) @Preview( name = "Dark - Primary", group = "Light/Dark - Primary", showBackground = true, backgroundColor = DARK_GRAY_W500, uiMode = UI_MODE_NIGHT_YES, ) annotation class PreviewPrimaryBackground Create multipreviews
  38. @Preview( name = "Light - Secondary", group = "Light/Dark -

    Secondary", showBackground = true, backgroundColor = GRAY_W100, ) @Preview( name = "Dark - Secondary", group = "Light/Dark - Secondary", showBackground = true, backgroundColor = DARK_GRAY_W100, uiMode = UI_MODE_NIGHT_YES, ) annotation class PreviewSecondaryBackground Create multipreviews
  39. @Preview( name = "Light - Secondary", group = "Light/Dark -

    Secondary", showBackground = true, backgroundColor = GRAY_W100, ) @Preview( name = "Dark - Secondary", group = "Light/Dark - Secondary", showBackground = true, backgroundColor = DARK_GRAY_W100, uiMode = UI_MODE_NIGHT_YES, ) annotation class PreviewSecondaryBackground Create multipreviews
  40. #DevFestVenezia @istvanjuhos.dev @Composable private fun ListItemPreview() { AppTheme { ListItem(

    text = "List item", onClick = {}, ) } } Create multipreviews @PreviewPrimaryBackground @PreviewSecondaryBackground annotation class PreviewAllBackgrounds
  41. #DevFestVenezia @istvanjuhos.dev @PreviewAllBackgrounds @Composable private fun ListItemPreview() { AppTheme {

    ListItem( text = "List item", onClick = {}, ) } } Create multipreviews @PreviewPrimaryBackground @PreviewSecondaryBackground annotation class PreviewAllBackgrounds
  42. #DevFestVenezia @istvanjuhos.dev Multipreview templates androidx.compose.ui.tooling.preview @PreviewLightDark @PreviewFontScale @Previe w​ ScreenSizes

    @PreviewDynamicColors ✅ developer.android.com/develop/ui/compose/tooling/previews#multipreview-templates
  43. #DevFestVenezia @istvanjuhos.dev No multipreview support yet @Preview @Preview annotation class

    PreviewPrimaryBackground @PreviewLightDark @PreviewFontScale @Previe w​ ScreenSizes @PreviewDynamicColors 😢 ❌
  44. #DevFestVenezia @istvanjuhos.dev Build custom tools - a new example @Composable

    fun PrimaryButton( text: String, @DrawableRes leadingIcon: Int? = null, onClick: () - > Unit, modifier: Modifier = Modifier ) { Button( colors = ButtonDefaults.buttonColors().copy( containerColor = AppTheme.colors.background, ), elevation = ButtonDefaults.buttonElevation(4.dp), modifier = modifier, onClick = onClick, ) { Row(verticalAlignment = CenterVertically) { leadingIcon ?. let { Image( painter = painterResource(id = leadingIcon), contentDescription = null, colorFilter = ColorFilter.tint(AppTheme.colors.primaryButtonText), modifier = Modifier.size(24.dp) ) } Text( text = text, style = AppTheme.typography.labelMedium, color = AppTheme.colors.primaryButtonText, modifier = Modifier.padding(start = 8.dp) ) } } }
  45. #DevFestVenezia @istvanjuhos.dev Let’s build our preview @PreviewLightDark @Composable private fun

    PrimaryButtonPreview() { PrimaryButton( text = "Primary Button", leadingIcon = R.drawable.ic_add, onClick = {}, ) }
  46. #DevFestVenezia @istvanjuhos.dev Let’s build our preview @PreviewLightDark @Composable private fun

    PrimaryButtonPreview() { PrimaryButton( text = "Primary Button", leadingIcon = R.drawable.ic_add, onClick = {}, ) }
  47. #DevFestVenezia @istvanjuhos.dev Something’s missing… @PreviewLightDark @Composable private fun PrimaryButtonPreview() {

    PrimaryButton( text = "Primary Button", leadingIcon = R.drawable.ic_add, onClick = {}, ) }
  48. #DevFestVenezia @istvanjuhos.dev @PreviewLightDark @Composable private fun PrimaryButtonPreview() { AppTheme {

    PrimaryButton( text = "Primary Button", leadingIcon = R.drawable.ic_add, onClick = {}, ) } } Something’s missing… the theme 🤦
  49. #DevFestVenezia @istvanjuhos.dev @PreviewLightDark @Composable private fun PrimaryButtonPreview() { AppTheme {

    PrimaryButton( text = "Primary Button", leadingIcon = R.drawable.ic_add, onClick = {}, ) } } Something’s missing… the theme 🤦
  50. #DevFestVenezia @istvanjuhos.dev @PreviewLightDark @Composable private fun PrimaryButtonPreview() { AppTheme {

    PrimaryButton( text = "Primary Button", leadingIcon = R.drawable.ic_add, onClick = {}, ) } } … and flexibility 💧
  51. #DevFestVenezia @istvanjuhos.dev @PreviewLightDark @Composable private fun PrimaryButtonPreview() { AppTheme {

    PrimaryButton( text = "Primary Button", leadingIcon = R.drawable.ic_add, onClick = {}, ) } } … and flexibility 💧 🫸
  52. #DevFestVenezia @istvanjuhos.dev @PreviewLightDark @Composable private fun PrimaryButtonPreview() { AppTheme {

    PrimaryButton( text = "Primary Button", leadingIcon = R.drawable.ic_add, onClick = {}, ) } } … and flexibility
  53. #DevFestVenezia @istvanjuhos.dev @Composable fun PreviewBox( modifier: Modifier = Modifier, content:

    @Composable () -> Unit, ) { AppTheme { content() } } Building preview tools
  54. #DevFestVenezia @istvanjuhos.dev @Composable fun PreviewBox( modifier: Modifier = Modifier, content:

    @Composable () -> Unit, ) { AppTheme { Box { content() } } } Building preview tools
  55. #DevFestVenezia @istvanjuhos.dev @Composable fun PreviewBox( modifier: Modifier = Modifier, backgroundColor:

    Color = AppTheme.colors.backgroundSecondary, content: @Composable () -> Unit, ) { AppTheme { Box { content() } } } Building preview tools
  56. #DevFestVenezia @istvanjuhos.dev @Composable fun PreviewBox( modifier: Modifier = Modifier, backgroundColor:

    Color = AppTheme.colors.backgroundSecondary, content: @Composable () -> Unit, ) { AppTheme { Box( modifier = modifier .background(backgroundColor), ) { content() } } } Building preview tools
  57. #DevFestVenezia @istvanjuhos.dev @Composable fun PreviewBox( modifier: Modifier = Modifier, backgroundColor:

    @Composable () -> Color = { AppTheme.colors.backgroundSecondary }, content: @Composable () -> Unit, ) { AppTheme { Box( modifier = modifier .background(backgroundColor()), ) { content() } } } Building preview tools
  58. #DevFestVenezia @istvanjuhos.dev @Composable fun PreviewBox( modifier: Modifier = Modifier, backgroundColor:

    @Composable () -> Color = { AppTheme.colors.backgroundSecondary }, content: @Composable () -> Unit, ) { AppTheme { Box( modifier = modifier .background(backgroundColor()), ) { content() } } } Building preview tools
  59. #DevFestVenezia @istvanjuhos.dev @Composable fun PreviewBox( modifier: Modifier = Modifier, backgroundColor:

    @Composable () -> Color = { AppTheme.colors.backgroundSecondary }, content: @Composable () -> Unit, ) { AppTheme { Box( ... ) { content() } } } Building preview tools
  60. #DevFestVenezia @istvanjuhos.dev @Composable fun PreviewBox( modifier: Modifier = Modifier, backgroundColor:

    @Composable () -> Color = { AppTheme.colors.backgroundSecondary }, paddingValues: PaddingValues = PaddingValues(4.dp), content: @Composable () -> Unit, ) { AppTheme { Box( ... ) { content() } } } Building preview tools
  61. #DevFestVenezia @istvanjuhos.dev @Composable fun Previe w​ Box( ... content: @Composable

    () -> Unit, ) { AppTheme { Box( ... ) { content() } } } Building preview tools
  62. #DevFestVenezia @istvanjuhos.dev @Composable fun Previe w​ Column( ... content: @Composable

    () -> Unit, ) { AppTheme { Column( ... ) { content() } } } Building preview tools
  63. #DevFestVenezia @istvanjuhos.dev @Composable fun PreviewDialog( modifier: Modifier = Modifier, factory:

    (context: Context) -> Dialog, ) { PreviewBox( contentPadding = PaddingValues(), ) { AndroidView( modifier = modifier, factory = { context -> val dialog = factory(context) dialog.create() val view = dialog.findViewById<View>(android.R.id.content) (view.parent as ViewGroup).removeView(view) view }, ) } } Building preview tools
  64. #DevFestVenezia @istvanjuhos.dev @Composable fun PreviewDialog( modifier: Modifier = Modifier, factory:

    (context: Context) -> Dialog, ) { PreviewBox( contentPadding = PaddingValues(), ) { AndroidView( modifier = modifier, factory = { context -> val dialog = factory(context) dialog.create() val view = dialog.findViewById<View>(android.R.id.content) (view.parent as ViewGroup).removeView(view) view }, ) } } Building preview tools
  65. #DevFestVenezia @istvanjuhos.dev Override CompositionLocals @Composable fun PreviewColumn( ... layoutDirection: LayoutDirection

    = LayoutDirection.Ltr, content: @Composable () -> Unit, ) { AppTheme { Column( ... ) { content() } } }
  66. #DevFestVenezia @istvanjuhos.dev Override CompositionLocals @Composable fun PreviewColumn( ... layoutDirection: LayoutDirection

    = LayoutDirection.Ltr, content: @Composable () -> Unit, ) { CompositionLocalProvider( LocalLayoutDirection provides layoutDirection, ) { AppTheme { Column( ... ) { content() } } } }
  67. #DevFestVenezia @istvanjuhos.dev Override CompositionLocals @PreviewLightDark @Composable private fun PreviewColumnPreview() {

    PreviewColumn( layoutDirection = LayoutDirection.Ltr, ) { PrimaryButton( ... ) ListItem( ... ) } }
  68. #DevFestVenezia @istvanjuhos.dev Override CompositionLocals @PreviewLightDark @Composable private fun PreviewColumnPreview() {

    PreviewColumn( layoutDirection = LayoutDirection.Rtl, ) { PrimaryButton( ... ) ListItem( ... ) } }
  69. #DevFestVenezia @istvanjuhos.dev Override CompositionLocals @PreviewLightDark @Composable private fun PreviewColumnPreview() {

    PreviewColumn( layoutDirection = LayoutDirection.Rtl, ) { PrimaryButton( .. . ) ListItem( .. . ) } }
  70. #DevFestVenezia @istvanjuhos.dev Override CompositionLocals @Preview @Composable private fun PreviewColumnPreview() {

    PreviewColumn( layoutDirection = LayoutDirection.Rtl, ) { PrimaryButton( .. . ) ListItem( .. . ) } }
  71. #DevFestVenezia @istvanjuhos.dev Override CompositionLocals @Preview @Composable private fun PreviewColumnPreview() {

    PreviewColumn( layoutDirection = LayoutDirection.Rtl, ) { PrimaryButton( .. . ) ListItem( .. . ) } }
  72. #DevFestVenezia @istvanjuhos.dev Make previews interactive @Composable fun FloatingPinMapOverlay( isLifted: Boolean,

    modifier: Modifier = Modifier, ) { /* Some beautifully animated content */ }
  73. #DevFestVenezia @istvanjuhos.dev Make previews interactive @Composable fun FloatingPinMapOverlay( isLifted: Boolean,

    modifier: Modifier = Modifier, ) { /* Some beautifully animated content */ }
  74. #DevFestVenezia @istvanjuhos.dev Make previews interactive @Composable fun FloatingPinMapOverlay( isLifted: Boolean,

    modifier: Modifier = Modifier, ) { /* Some beautifully animated content */ }
  75. #DevFestVenezia @istvanjuhos.dev Make previews interactive @Composable fun FloatingPinMapOverlay( isLifted: Boolean,

    modifier: Modifier = Modifier, ) { /* Some beautifully animated content */ } @Preview @Composable private fun PreviewFloatingPinMapOverlay() { var isLifted by remember { mutableStateOf(false) } PreviewBox( . .. modifier = Modifier.clickable { isLifted = !isLifted }, ) { FloatingPinMapOverlay( isLifted = isLifted, ) } }
  76. #DevFestVenezia @istvanjuhos.dev Make previews interactive @Composable fun FloatingPinMapOverlay( isLifted: Boolean,

    modifier: Modifier = Modifier, ) { /* Some beautifully animated content */ } @Preview @Composable private fun PreviewFloatingPinMapOverlay() { var isLifted by remember { mutableStateOf(false) } PreviewBox( . .. modifier = Modifier.clickable { isLifted = !isLifted }, ) { FloatingPinMapOverlay( isLifted = isLifted, ) } }
  77. #DevFestVenezia @istvanjuhos.dev Make previews interactive @Composable fun FloatingPinMapOverlay( isLifted: Boolean,

    modifier: Modifier = Modifier, ) { /* Some beautifully animated content */ } @Preview @Composable private fun PreviewFloatingPinMapOverlay() { var isLifted by remember { mutableStateOf(false) } PreviewBox( . .. modifier = Modifier.clickable { isLifted = !isLifted }, ) { FloatingPinMapOverlay( isLifted = isLifted, ) } }
  78. #DevFestVenezia @istvanjuhos.dev Make previews interactive @Composable fun FloatingPinMapOverlay( isLifted: Boolean,

    modifier: Modifier = Modifier, ) { /* Some beautifully animated content */ } @Preview @Composable private fun PreviewFloatingPinMapOverlay() { var isLifted by remember { mutableStateOf(false) } PreviewBox( . .. modifier = Modifier.clickable { isLifted = !isLifted }, ) { FloatingPinMapOverlay( isLifted = isLifted, ) } }
  79. #DevFestVenezia @istvanjuhos.dev Make previews interactive @Composable fun FloatingPinMapOverlay( isLifted: Boolean,

    modifier: Modifier = Modifier, ) { /* Some beautifully animated content */ } @Preview @Composable private fun PreviewFloatingPinMapOverlay() { var isLifted by remember { mutableStateOf(false) } PreviewBox( . .. modifier = Modifier.clickable { isLifted = !isLifted }, ) { FloatingPinMapOverlay( isLifted = isLifted, ) } }
  80. #DevFestVenezia @istvanjuhos.dev Some more ideas • Generate previews with PreviewParemeterProviders

    • Providing Composables as preview parameters proandroiddev.com/using-previewparameters-and-providing-composables-to-jetpack-compose-previews-5b1f5a8fe192
  81. #DevFestVenezia @istvanjuhos.dev Some more ideas • Use previews to build

    a component showcase github.com/airbnb/Showkase
  82. #DevFestVenezia @istvanjuhos.dev Some more ideas • Use previews for screenshot

    testing developer.android.com/studio/preview/compose-screenshot-testing
  83. #DevFestVenezia @istvanjuhos.dev Some more ideas • … or just make

    the whole app runnable in Preview 🤷 medium.com/whatnot-engineering/preview-driven-development-with-compose-f7a5beee95aa
  84. #DevFestVenezia @istvanjuhos.dev Resources • developer.android.com/develop/ui/compose/tooling/previews • developer.android.com/topic/performance/rendering/overdraw • proandroiddev.com/using-previewparameters-and-providing-composables- to-jetpack-compose-previews-5b1f5a8fe192

    • github.com/airbnb/Showkase • developer.android.com/studio/preview/compose-screenshot-testing • medium.com/whatnot-engineering/preview-driven-development-with- compose-f7a5beee95aa • Good old fi eld experience 😅
  85. Practical Tips and Tricks to Improve Your Compose Previews •

    Compose previews are code, treat them with care • Compose custom reusable tools • Simplify previews as much as possible • but go wild if it’s worth it! 😎 istvanjuhos.dev István Juhos Photo by Glenn Carstens-Peters