Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Compose Previews as a Power User
Search
Subhrajyoti Sen
October 06, 2024
Programming
250
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Compose Previews as a Power User
Subhrajyoti Sen
October 06, 2024
More Decks by Subhrajyoti Sen
See All by Subhrajyoti Sen
Understanding Incremental Processing in the JVM World
subhrajyotisen
0
65
Updated Lessons from a KMP Developer's Toolkit
subhrajyotisen
0
85
Building Mobile Apps and Scaling them
subhrajyotisen
0
82
Understanding WindowInsets
subhrajyotisen
0
280
Exploring a KMM Developer’s Toolkit
subhrajyotisen
1
290
Shipping Apps Confidently with Firebase
subhrajyotisen
0
150
Understanding WindowInsets - Android Worldwide
subhrajyotisen
0
420
Understanding WindowInsets
subhrajyotisen
1
260
Demystifying Styles and Themes
subhrajyotisen
0
300
Other Decks in Programming
See All in Programming
Agents on Rails - Rails at Scale 2026
irinanazarova
0
530
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
170
コードレビューのボトルネックを"する側"と"される側"の両面から解消する
yub0n
2
1.6k
個人開発者よ、Honoを使え(おじさんver)
tanahiro2010
2
250
wkhtmltopdfの次どうするか問題2026
willnet
2
1.9k
Java 27新機能 / Java 27 new features
kishida
2
220
Kubernetes祭り #2 OP/ED
bells17
0
110
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
630
カツオ、ご期待ください
suneo3476
0
170
パーソナライズPodcastを作った話
repunit11
0
130
[2026-09-26]空論ジェネリックプロセス~テスト資産とAIで紡ぐ、再現可能なパフォーマンスチューニングの話~
tosite
0
270
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
8
2.1k
Featured
See All Featured
The Limits of Empathy - UXLibs8
cassininazir
2
720
YesSQL, Process and Tooling at Scale
rocio
174
15k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
280
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.6k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
1k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.5k
Statistics for Hackers
jakevdp
799
230k
So, you think you're a good person
axbom
PRO
2
2.2k
KATA
mclloyd
PRO
35
16k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
280
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
320
Building a Scalable Design System with Sketch
lauravandoore
464
34k
Transcript
Compose Previews as a Power User Chennai Subhrajyoti Sen Motive
Simple Previews
@Composable fun BorrowedItemRowPreview() { BorrowedItemRow( item = BorrowItem( id =
0, itemName = "XBox Series X", borrowerName = "Steve", borrowDate = "2-11-2023" ) ) }
@Preview @Composable fun BorrowedItemRowPreview() { BorrowedItemRow( item = BorrowItem( id
= 0, itemName = "XBox Series X", borrowerName = "Steve", borrowDate = "2-11-2023" ) ) }
@Preview @Composable fun BorrowedItemRowPreview() { BorrowedItemRow( item = BorrowItem( id
= 0, itemName = "XBoz Series X", borrowerName = "Steve", borrowDate = "2-11-2023" ) ) }
None
Available Arguments • name • group • uiMode • locale
• showSystemUi • showBackground • device • apiLevel
Dark Mode
@Preview(uiMode = UI_MODE_NIGHT_YES) @Composable fun BorrowedItemRowDevicePreview() { BorrowTheme { BorrowedItemRow(
item = //.. ) } }
None
Multi Preview Annotation
@Preview(uiMode = UI_MODE_NIGHT_NO) @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable fun BorrowedItemRowDevicePreview() {
BorrowTheme { BorrowedItemRow( item = //.. ) } }
@Preview(uiMode = UI_MODE_NIGHT_NO) @Preview(uiMode = UI_MODE_NIGHT_YES) annotation class LightDarkThemePreview
@LightDarkThemePreview @Composable fun BorrowedItemRowDevicePreview() { BorrowTheme { BorrowedItemRow( item =
//.. ) } }
@LightDarkThemePreview @Composable fun BorrowedItemRowDevicePreview() { BorrowTheme { BorrowedItemRow( item =
//.. ) } }
None
@Preview( showSystemUi = true, device = Devices.NEXUS_5X ) @Preview( showSystemUi
= true, device = Devices.NEXUS_10 ) annotation class MultiDevicePreview
@Preview( showSystemUi = true, device = Devices.NEXUS_5X ) @Preview( showSystemUi
= true, device = Devices.NEXUS_10 ) annotation class MultiDevicePreview
@Preview(locale = "en") @Preview(locale = "fr-rCA") @Preview(locale = "es-rUS") annotation
class MultiLocalePreview Valid locale format: https://developer.android.com/guide/topics/resources/provid ing-resources#LocaleQualifier
@LightDarkThemePreview @MultiLocalePreview annotation class MultiLocaleLightDarkPreview
Dataset Driven Preview
None
@Preview @Composable fun BorrowedItemRowPreview() { BorrowedItemRow( item = BorrowItem( id
= 0, itemName = "XBox Series X", borrowerName = "Steve", borrowDate = "2-11-2023" ) ) } @Preview @Composable fun BorrowedItemRowPreview() { BorrowedItemRow( item = BorrowItem( id = 0, itemName = "PlayStation", borrowerName = "Steve", borrowDate = "2-11-2023" ) ) }
class BorrowItemsProvider : PreviewParameterProvider<BorrowItem> { override val values = sequenceOf(
BorrowItem( id = 0, itemName = "PlayStation", borrowerName = "Steve", borrowDate = "2-11-2022" ), BorrowItem( id = 0, itemName = "XBox", borrowerName = "Steve", borrowDate = "2-11-2022" ) ) }
class BorrowItemsProvider : PreviewParameterProvider<BorrowItem> { override val values = sequenceOf(
BorrowItem( id = 0, itemName = "PlayStation", borrowerName = "Steve", borrowDate = "2-11-2022" ), BorrowItem( id = 0, itemName = "XBox", borrowerName = "Steve", borrowDate = "2-11-2022" ) ) }
@Preview @Composable fun BorrowedItemRowPreview( @PreviewParameter(BorrowItemsProvider::class) item: BorrowItem ) { BorrowedItemRow(
item ) }
@Preview @Composable fun BorrowedItemRowPreview( @PreviewParameter(BorrowItemsProvider::class) item: BorrowItem ) { BorrowedItemRow(
item ) }
Declutter using Groups
@MultiLocaleLightDarkPreview @Composable fun BorrowedItemRowDevicePreview() { BorrowTheme { BorrowedItemRow( item =
//.. ) } }
None
@Preview(locale = "en", group = "English") @Preview(locale = "fr-rCA", group
= "Canadian French") @Preview(locale = "es-rUS", group = "US Spanish") annotation class MultiLocalePreview
None
Local Inspection
None
@Composable fun BorrowedItemRow(item: BorrowItem) { var expanded by remember {
mutableStateOf(false) } // this will only affect previews if (LocalInspectionMode.current) { expanded = true } //.. }
@Composable fun BorrowedItemRow(item: BorrowItem) { var expanded by remember {
mutableStateOf(false) } // this will only affect previews if (LocalInspectionMode.current) { expanded = true } //.. }
Showkase
None
@ShowkaseComposable(group = "Individual rows") @Preview @Composable fun BorrowedItemRowExpandedPreview() { BorrowTheme
{ BorrowedItemRow( //.. ) } }
@ShowkaseComposable(group = "Individual rows") @Preview @Composable fun BorrowedItemRowExpandedPreview() { BorrowTheme
{ BorrowedItemRow( //.. ) } }
@ShowkaseComposable(group = "Individual rows") @Composable @Preview fun BorrowedItemRowCollapsedPreview() { CompositionLocalProvider(LocalInspectionMode
provides false) { BorrowTheme { BorrowedItemRow( //.. ) } } }
None
None
None
Animation Previews
None
None
updateTransition Supported Animations AnimatedVisibility animate*AsState rememberInfiniteTransition CrossFade AnimatedContent
Screenshot Testing
Available Options
Paparazzi Available Options
Paparazzi Roborazzi Available Options
Paparazzi Roborazzi Compose Preview Available Options
Paparazzi
Works on JVM Paparazzi
Works on JVM Based on Layoutlib Paparazzi
Works on JVM Based on Layoutlib Needs JUnit tests Paparazzi
Works on JVM Based on Layoutlib Needs JUnit tests Paparazzi
Supports Views
Works on JVM Based on Layoutlib Needs JUnit tests Paparazzi
Supports Views Emulates Production
class PaparazziTests { @get:Rule val paparazzi = Paparazzi( deviceConfig =
PIXEL_5.copy(nightMode = NightMode.NIGHT), renderingMode = RenderingMode.SHRINK ) }
class PaparazziTests { @get:Rule val paparazzi = Paparazzi( deviceConfig =
PIXEL_5.copy(nightMode = NightMode.NIGHT), renderingMode = RenderingMode.SHRINK ) }
class PaparazziTests { //.. @Test fun launchComposable() { paparazzi.snapshot {
BorrowTheme { BorrowedItemRow( item = //.. ) } } } }
class PaparazziTests { //.. @Test fun launchComposable() { paparazzi.snapshot {
CompositionLocalProvider(LocalInspectionMode provides true) { BorrowTheme { BorrowedItemRow( item = //.. ) } } } } }
class PaparazziTests { //.. @Test fun launchComposable() { paparazzi.snapshot {
CompositionLocalProvider(LocalInspectionMode provides true) { BorrowTheme { BorrowedItemRow( item = //.. ) } } } } }
Baseline
After changes
Failure Comparison
Compose Preview Screenshot
Works on JVM Compose Preview Screenshot
Works on JVM Based on Layoutlib Compose Preview Screenshot
Works on JVM Based on Layoutlib Fully Automated Compose Preview
Screenshot
Works on JVM Based on Layoutlib Fully Automated Compose Preview
Screenshot Needs a special directory
Works on JVM Based on Layoutlib Fully Automated Compose Preview
Screenshot Needs a special directory Emulates Debug
Compose Preview Screenshot - Source
Compose Preview Screenshot - Source @LightDarkThemePreview @Composable fun BorrowedItemRowPreview( @PreviewParameter(BorrowItemsProvider::class)
item: BorrowItem ) { BorrowedItemRow( item ) }
Compose Preview Screenshot - Destination
Screen Comparison
Screen Comparison
Can’t decide? sergio-sastre/ComposablePreviewScanner
Further Exploration https://github.com/takahirom/roborazzi Composable Preview Driven Development: TDD-fying your UI
with ease!
Questions?
Thank You! Chennai