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 Preview活用事例
Search
Ritsuki Otsuka
September 25, 2024
Technology
320
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
東急カードプラスのCompose Preview活用事例
DroidKaigi.onCompletion { 2024@Online }
https://yumemi.connpass.com/event/329691/
Ritsuki Otsuka
September 25, 2024
Other Decks in Technology
See All in Technology
Kiro Crewをはじめよう
kizawa2020
1
160
PHPカンファレンス関西の招待状 / Invitation to PHP Conference Kansai
ykanoh
0
210
ソフトウェア ファクトリー - 再現性のあるソフトウェアの工場づくり / Software factory
iktakahiro
6
5.1k
JAWSUG TOHOKU 青森支部 「LoGoチャット」のAWS移行で 乗り越えたこと
taketakekaho
0
340
AI時代のPRレビューにどう向き合うか?
kairim0
1
240
Active Record Connection Adaptersにおける長年の課題に再び取り組む
yahonda
0
200
CTO Night|NotionのAIエージェントとFDE
kzkhykw1991
0
230
TinyGoでオブザーバビリティ?OpenTelemetryはTinyGoで使えるのか / Is OpenTelemetry available in TinyGo environment?
ymotongpoo
2
140
脆弱性診断って、何をしているの? 〜弱点を見つけて、会社の改善につなげるまで〜
keeg
0
930
トークン化預金DCJPYの取り組みと活用ユースケース
finengine
0
160
その Valkey 使いこなしていますか?
onk
PRO
5
1.6k
OptunaHub: ブラックボックス最適化のためのプラットフォーム
pfn
PRO
0
140
Featured
See All Featured
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.1k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
How to Talk to Developers About Accessibility
jct
2
580
Technical Leadership for Architectural Decision Making
baasie
3
600
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.4k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
2
360
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.9k
WENDY [Excerpt]
tessaabrams
14
40k
How GitHub (no longer) Works
holman
316
150k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Being A Developer After 40
akosma
92
590k
4 Signs Your Business is Dying
shpigford
187
23k
Transcript
東急カードプラスの Compose Preview 活用事例 東急株式会社 デジタルプラットフォーム URBAN HACKS 大塚 立樹
自己紹介 2 • 大塚 立樹 / Ritsuki Otsuka • 東急株式会社
URBAN HACKS • Androidエンジニア(3年目) • 「東急カードプラス」Androidアプリの開発を担当
東急カードプラス 3 • TOKYU CARDのご利用明細や、TOKYU POINT CARDのポイント残高など を確認できる • 東急沿線エリアのタイムリーでおトクな情報や、ポイントがお得に貯まる方法など
も紹介 • 2023年3月にリニューアルリリース • 技術スタック • Jetpack Compose (100%) • Jetpack Navigation • Kotlin Coroutines and Flow • Dagger Hilt • etc…
東急カードプラスでの Previewの使用目的
東急カードプラスでの Previewの使用目的 5 • 実装者以外や新規メンバーを含む開発者が画面の実装を確認しても、その画面にどのようなUIのパ ターンがあるのか一目でわかるようにしたい • フォントサイズを大きくした時や、折りたたみ端末等のデバイスでのレイアウト崩れを早期に検知したい
東急カードプラスの画面実装
東急カードプラスの画面実装 7
東急カードプラスの画面実装 8 1. TOKYU POINT残高 2. お支払い額 3. ご利用実績 4.
ピックアップ 5. かしこいポイントの貯め方
東急カードプラスの画面実装 9 1. TOKYU POINT残高 → TokyuPointSection 2. お支払い額 →
PaymentAmountSection 3. ご利用実績 → MonthlyPaymentsSection 4. ピックアップ → PickupSection 5. かしこいポイントの貯め方 → PointEarningTipsSection
東急カードプラスの画面実装 10 1. TOKYU POINT残高 → TokyuPointSection 2. お支払い額 →
PaymentAmountSection 3. ご利用実績 → MonthlyPaymentsSection 4. ピックアップ → PickupSection 5. かしこいポイントの貯め方 → PointEarningTipsSection ➡ SectionごとにUI Stateを作成
東急カードプラスの画面実装 11 data class HomeUiState( // 1. TOKYU POINT残高 val
tokyuPointSectionUiState: TokyuPointSectionUiState, // 2. お支払い額 val paymentAmountSectionUiState: PaymentAmountSectionUiState?, // 3. ご利用実績 val monthlyPaymentsSectionUiState: MonthlyPaymentsSectionUiState? // 4. ピックアップ val pickupSectionUiState: PickupSectionUiState?, // 5. かしこいポイントの貯め方 val pointEarningTipsSectionUiState: PointEarningTipsSectionUiState ) : HomeUiState
東急カードプラスの画面実装 12 Previewを作成する対象UI • Screen(画面の単位) • Section(画面内の意味のあるまとまり)
東急カードプラスの画面実装 13 ちなみに・・・ この画面実装は、DroidKaigi 2023 公式アプリを参考にしています! https://github.com/DroidKaigi/conference-app-2023
複雑なUI Stateのパターンを Previewする
複雑なUI Stateのパターンを Previewする 15
複雑なUI Stateのパターンを Previewする 16 TOKYU POINT残高表示の基本UIパターン 1. ポイント表示状態 2. ポイント非表示状態
3. ローディング状態
複雑なUI Stateのパターンを Previewする 17 TOKYU POINT残高表示の基本UIパターン 1. ポイント表示状態 2. ポイント非表示状態
3. ローディング状態 ❎ 時間ごとの UIパターン 1. 朝(4:00〜10:59) 2. 昼(11:00〜16:59) 3. 夜(17:00〜3:59)
複雑なUI Stateのパターンを Previewする 18 PreviewParameter • 複数パターンのPreviewを作成したいときに活用できる • リスト形式のデータセットをPreview Composableに渡してPreviewが表示できる
複雑なUI Stateのパターンを Previewする 19 @Preview @Composable private fun TokyuPointSectionPreview( @PreviewParameter(TokyuPointSectionPreviewParameterProvider::class)
uiState: TokyuPointSectionUiState ) { HachiTheme { TokyuPointSection(tokyuPointSectionUiState = uiState) } }
複雑なUI Stateのパターンを Previewする 20 @Preview @Composable private fun TokyuPointSectionPreview( @PreviewParameter(TokyuPointSectionPreviewParameterProvider::class)
uiState: TokyuPointSectionUiState ) { HachiTheme { TokyuPointSection(tokyuPointSectionUiState = uiState) } }
複雑なUI Stateのパターンを Previewする 21 class TokyuPointSectionPreviewParameterProvider : PreviewParameterProvider<TokyuPointSectionUiState> { override
val values: Sequence<TokyuPointSectionUiState> = sequenceOf( // ローディング状態 TokyuPointSectionUiState.Loading, // ポイント表示状態 x 時間帯 TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Morning), TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Noon), TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Night), // ポイント非表示状態 x 時間帯 TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Morning), TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Noon), TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Night) ) }
複雑なUI Stateのパターンを Previewする 22 class TokyuPointSectionPreviewParameterProvider : PreviewParameterProvider<TokyuPointSectionUiState> { override
val values: Sequence<TokyuPointSectionUiState> = sequenceOf( // ローディング状態 TokyuPointSectionUiState.Loading, // ポイント表示状態 x 時間帯 TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Morning), TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Noon), TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Night), // ポイント非表示状態 x 時間帯 TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Morning), TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Noon), TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Night) ) }
複雑なUI Stateのパターンを Previewする 23 class TokyuPointSectionPreviewParameterProvider : PreviewParameterProvider<TokyuPointSectionUiState> { override
val values: Sequence<TokyuPointSectionUiState> = sequenceOf( // ローディング状態 TokyuPointSectionUiState.Loading, // ポイント表示状態 x 時間帯 TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Morning), TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Noon), TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Night), // ポイント非表示状態 x 時間帯 TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Morning), TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Noon), TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Night) ) }
複雑なUI Stateのパターンを Previewする 24 class TokyuPointSectionPreviewParameterProvider : PreviewParameterProvider<TokyuPointSectionUiState> { override
val values: Sequence<TokyuPointSectionUiState> = sequenceOf( // ローディング状態 TokyuPointSectionUiState.Loading, // ポイント表示状態 x 時間帯 TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Morning), TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Noon), TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Night), // ポイント非表示状態 x 時間帯 TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Morning), TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Noon), TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Night) ) }
複雑なUI Stateのパターンを Previewする 25 class TokyuPointSectionPreviewParameterProvider : PreviewParameterProvider<TokyuPointSectionUiState> { override
val values: Sequence<TokyuPointSectionUiState> = sequenceOf( // ローディング状態 TokyuPointSectionUiState.Loading, // ポイント表示状態 x 時間帯 TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Morning), TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Noon), TokyuPointSectionUiState.PointAmountVisible(pointAmount = 1000, timePeriod = TimePeriod.Night), // ポイント非表示状態 x 時間帯 TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Morning), TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Noon), TokyuPointSectionUiState.PointAmountHidden(pointAmount = 1000, timePeriod = TimePeriod.Night) ) }
複雑なUI Stateのパターンを Previewする 26 @Preview @Composable private fun TokyuPointSectionPreview( @PreviewParameter(TokyuPointSectionPreviewParameterProvider::class)
uiState: TokyuPointSectionUiState ) { HachiTheme { TokyuPointSection(tokyuPointSectionUiState = uiState) } }
カスタムマルチプレビューアノテーション
カスタムマルチプレビューアノテーション 28 • カスタムで定義された、複数の@Previewを含むアノテーションクラス • カスタムマルチプレビューアノテーションを使用することで、異なるプレビューが同時に自動で表示できる • 異なるデバイスの種類や、フォントサイズなどを一度にプレビューするのに便利
カスタムマルチプレビューアノテーション 29 @Preview(name = "1 デフォルト") @Preview( name = "2
最大フォントサイズ", fontScale = 2.0f ) @Preview(name = "3 Foldable", device = Devices.FOLDABLE) annotation class HachiPreviews 1. 通常端末サイズ 2. 最大フォントサイズ 3. 折りたたみ端末
カスタムマルチプレビューアノテーション 30 @Preview(name = "1 デフォルト") @Preview( name = "2
最大フォントサイズ", fontScale = 2.0f ) @Preview(name = "3 Foldable", device = Devices.FOLDABLE) annotation class HachiPreviews
カスタムマルチプレビューアノテーション 31 @Preview(name = "1 デフォルト") @Preview( name = "2
最大フォントサイズ", fontScale = 2.0f ) @Preview(name = "3 Foldable", device = Devices.FOLDABLE) annotation class HachiPreviews
カスタムマルチプレビューアノテーション 32 @Preview(name = "1 デフォルト") @Preview( name = "2
最大フォントサイズ", fontScale = 2.0f ) @Preview(name = "3 Foldable", device = Devices.FOLDABLE) annotation class HachiPreviews
カスタムマルチプレビューアノテーション 33 @Preview(name = "1 デフォルト") @Preview( name = "2
最大フォントサイズ", fontScale = 2.0f ) @Preview(name = "3 Foldable", device = Devices.FOLDABLE) annotation class HachiPreviews
カスタムマルチプレビューアノテーション 34 @Preview @Composable private fun TokyuPointSectionPreview( @PreviewParameter(TokyuPointSectionPreviewParameterProvider::class) uiState: TokyuPointSectionUiState
) { HachiTheme { TokyuPointSection(tokyuPointSectionUiState = uiState) } } 👈 カスタムマルチプレビューに置き換える
カスタムマルチプレビューアノテーション 35 // @Preview @HachiPreviews @Composable private fun TokyuPointSectionPreview( @PreviewParameter(TokyuPointSectionPreviewParameterProvider::class)
uiState: TokyuPointSectionUiState ) { HachiTheme { TokyuPointSection(tokyuPointSectionUiState = uiState) } }
まとめ 36 東急カードプラスでは • PreviewParameterを用いて、実装者以外や新規メンバーを含む開発者が画面の実装を確認しても、 その画面にどのようなUIのパターンがあるのか一目でわかる状態を実現しています • カスタムマルチプレビューアノテーション を用いて、フォントサイズを大きくした際や、折りたたみ端末等 のデバイスでのレイアウト崩れを早期に検知できるように取り組んでいます
Thank you for listening! ご清聴ありがとうございました!