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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
74
Updated Lessons from a KMP Developer's Toolkit
subhrajyotisen
0
88
Building Mobile Apps and Scaling them
subhrajyotisen
0
85
Understanding WindowInsets
subhrajyotisen
0
280
Exploring a KMM Developer’s Toolkit
subhrajyotisen
1
290
Shipping Apps Confidently with Firebase
subhrajyotisen
0
160
Understanding WindowInsets - Android Worldwide
subhrajyotisen
0
430
Understanding WindowInsets
subhrajyotisen
1
260
Demystifying Styles and Themes
subhrajyotisen
0
310
Other Decks in Programming
See All in Programming
複雑なUIコンポーネントとの ⻑い付き合い⽅:波及するバグからテスト戦略を経て、安全な再設計へ
mixplace
0
500
Web Framework Benchmark Battle 2026, Any%
a_matsuda
3
3.1k
コーディング自動化の次へ。人の介入をゼロにするファクトリーとサポートAIによる実践
timakin
5
5k
[JA] Domain Modeling with Vanilla Rails: 「操作」から再考するRailsの設計論
yasaichi
4
1.7k
社内AIエージェント「Askワンバン」における コストチューニングの取り組み
t0yohei
0
130
Python Lambdaにおけるテストしやすい設計とAI支援の活用 / Designing Testable Python Lambda Functions with AI
kitano_yuichi
1
280
조합이폭발하는디자인시스템이걸눈으로도테스트하라고요
giljongyu
0
700
Coding with AI: How to trust the storyteller (AWS Community Day Adria, Ljubljana 2026)
slobodan
0
130
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
550
Modernizing iOS Apps
seyfoyun
0
150
JIS keyboard support in Omarchy
lef237
0
180
Getting Started with Vibe Coding
miccheng
0
170
Featured
See All Featured
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
920
Reality Check: Gamification 10 Years Later
codingconduct
0
2.4k
Discover your Explorer Soul
emna__ayadi
2
1.3k
Designing for Performance
lara
612
70k
Are puppies a ranking factor?
jonoalderson
2
4.1k
So, you think you're a good person
axbom
PRO
2
2.2k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.7k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
390
Context Engineering - Making Every Token Count
addyosmani
9
1.3k
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
290
Utilizing Notion as your number one productivity tool
mfonobong
4
630
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