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
Jetpack Compose Layout API
Search
Moyuru Aizawa
February 17, 2023
Programming
720
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Jetpack Compose Layout API
Moyuru Aizawa
February 17, 2023
More Decks by Moyuru Aizawa
See All by Moyuru Aizawa
BLUETOOTH_SCAN and iBeacon
lvla
1
150
graphicsLayer
lvla
0
300
BluetoothDevice.getName()に裏切られた話
lvla
0
430
Jetpack Composeで画像クロップ機能を実装する
lvla
0
1.3k
Jetpack Compose drag gesture and pinch gesture
lvla
1
4.4k
BLEを使ったアプリを継続的に開発するために
lvla
0
1.1k
RecyclerView.ItemAnimator
lvla
1
390
RecycledViewPool
lvla
1
300
CameraX
lvla
2
2.6k
Other Decks in Programming
See All in Programming
速く作れる。その次は、速く確かめられる開発へ 〜AIネイティブ開発を支える、Shift Down〜 / Can build fast. Next, moving to development where we can verify fast.
rkaga
5
3.3k
iOSDC Japan 2026 - Swiftで作って学ぼう!データベース自作入門
kaseken
2
170
thread_parallel_with_free-threaded_Python_and_NumPy.pdf
riku_sakamoto
0
340
App Intentsのビルドプロセスを支える技術
kntkymt
0
390
20260914 AIエージェント時代のPlatform Engineering LLM基盤とプロダクトの責務境界線
kanfab1
7
2.1k
巨大モノリシックアプリ モダン化大作戦
ktcryomm
1
1k
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
1
480
Security issues being discussed on Web Platforms
petamoriken
0
960
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
170
世界の中心で、AI(App Intents)をさけぶ ー App Intents中心設計の実践ガイド
touyou
0
600
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
300
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
180
Featured
See All Featured
Designing for Timeless Needs
cassininazir
1
480
What's in a price? How to price your products and services
michaelherold
247
13k
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
8k
Docker and Python
trallard
47
4.2k
Into the Great Unknown - MozCon
thekraken
41
2.7k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.6k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.3k
We Are The Robots
honzajavorek
0
380
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
670
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.4k
Site-Speed That Sticks
csswizardry
13
1.5k
Transcript
Layout API @MoyuruAizawa
Moyuru Aizawa Software Engineer of Catlog, RABO. Previously at Azit,
CyberAgent, and Eureka. Love Metal, Hardcore and EDM. MoyuruAizawa
None
Layout APIͱ?
‣ Column/Row͕෦Ͱ༻͍ͯ͠ΔAPI ‣ ContentͷϨΠΞτΛࣗ༝ʹܾఆͰ͖Δ ‣ ViewGroupLayoutManagerʹࣅͨଘࡏ ‣ Column/RowͰදݱͰ͖ͳ͍͕ConstraintLayoutBoxΛۦ͢Δ ͷͪΐͬͱ໘ɺͱ͍ͬͨͱ͖ʹศར ‣
ͦΜͳঢ়گ͋·Γͳ͍ Layout APIͱ?
@Composable inline fun Layout( content: @Composable @UiComposable () -> Unit,
modifier: Modifier = Modifier, measurePolicy: MeasurePolicy ) Layout API
@Composable inline fun Layout( content: @Composable @UiComposable () -> Unit,
modifier: Modifier = Modifier, measurePolicy: MeasurePolicy ) Layout API
‣ Layout APIͷཁͱͳΔInterface ‣ MeasurePolicyΛ࣮ͯ͠Layout APIʹ͢͜ͱͰɺࣗ༝ͳϨΠΞ τΛ࣮ݱͰ͖Δ MeasurePolicy
interface MeasurePolicy { fun MeasureScope.measure( measurables: List<Measurable>, constraints: Constraints ):
MeasureResult … } MeasurePolicy
SimpleͳRowͷMeasurePolicyΛ ࣮ͯ͠ΈΔ
class SimpleRowMeasurePolicy : MeasurePolicy { override fun MeasureScope.measure( measurables: List<Measurable>,
constraints: Constraints ): MeasureResult { … } } SimpleRowMeasurePolicy
val placeables = measurables.map { measurable -> measurable.measure(constraints.copy(minWidth = 0,
minHeight = 0)) } val parentWidth = placeables.sumOf { it.width } .coerceAtMost(constraints.maxWidth) val parentHeight = placeables.maxOf { it.height } .coerceAtMost(constraints.maxHeight) return layout(parentWidth, parentHeight) { var offsetX = 0 for (placeable in placeables) { placeable.place(offsetX, 0) offsetX += placeable.width if (offsetX > parentWidth) break } } MeasurePolicy#measure
val placeables = measurables.map { measurable -> measurable.measure(constraints.copy(minWidth = 0,
minHeight = 0)) } val parentWidth = placeables.sumOf { it.width } .coerceAtMost(constraints.maxWidth) val parentHeight = placeables.maxOf { it.height } .coerceAtMost(constraints.maxHeight) return layout(parentWidth, parentHeight) { var offsetX = 0 for (placeable in placeables) { placeable.place(offsetX, 0) offsetX += placeable.width if (offsetX > parentWidth) break } } measurables(children)Λmeasure֤ͯ͠ݸͷαΠζΛܾఆ͢Δ
val placeables = measurables.map { measurable -> measurable.measure(constraints.copy(minWidth = 0,
minHeight = 0)) } val parentWidth = placeables.sumOf { it.width } .coerceAtMost(constraints.maxWidth) val parentHeight = placeables.maxOf { it.height } .coerceAtMost(constraints.maxHeight) return layout(parentWidth, parentHeight) { var offsetX = 0 for (placeable in placeables) { placeable.place(offsetX, 0) offsetX += placeable.width if (offsetX > parentWidth) break } } placeablesͷαΠζΛΈͯͷαΠζΛܭࢉ͢Δ
val placeables = measurables.map { measurable -> measurable.measure(constraints.copy(minWidth = 0,
minHeight = 0)) } val parentWidth = placeables.sumOf { it.width } .coerceAtMost(constraints.maxWidth) val parentHeight = placeables.maxOf { it.height } .coerceAtMost(constraints.maxHeight) return layout(parentWidth, parentHeight) { var offsetX = 0 for (placeable in placeables) { placeable.place(offsetX, 0) offsetX += placeable.width if (offsetX > parentWidth) break } } placeablesΛplace͍ͯ͘͠
val placeables = measurables.map { measurable -> measurable.measure(constraints.copy(minWidth = 0,
minHeight = 0)) } val parentWidth = placeables.sumOf { it.width } .coerceAtMost(constraints.maxWidth) val parentHeight = placeables.maxOf { it.height } .coerceAtMost(constraints.maxHeight) return layout(parentWidth, parentHeight) { var offsetX = 0 for (placeable in placeables) { placeable.place(offsetX, 0) offsetX += placeable.width if (offsetX > parentWidth) break } } placeablesΛplace͍ͯ͘͠
val placeables = measurables.map { measurable -> measurable.measure(constraints.copy(minWidth = 0,
minHeight = 0)) } val parentWidth = placeables.sumOf { it.width } .coerceAtMost(constraints.maxWidth) val parentHeight = placeables.maxOf { it.height } .coerceAtMost(constraints.maxHeight) return layout(parentWidth, parentHeight) { var offsetX = 0 for (placeable in placeables) { placeable.place(offsetX, 0) offsetX += placeable.width if (offsetX > parentWidth) break } } placeablesΛplace͍ͯ͘͠
val placeables = measurables.map { measurable -> measurable.measure(constraints.copy(minWidth = 0,
minHeight = 0)) } val parentWidth = placeables.sumOf { it.width } .coerceAtMost(constraints.maxWidth) val parentHeight = placeables.maxOf { it.height } .coerceAtMost(constraints.maxHeight) return layout(parentWidth, parentHeight) { var offsetX = 0 for (placeable in placeables) { placeable.place(offsetX, 0) offsetX += placeable.width if (offsetX > parentWidth) break } } ஔͨ͠placeableͷwidth͚ͩoffsetʹՃࢉ͍ͯ͘͠
val placeables = measurables.map { measurable -> measurable.measure(constraints.copy(minWidth = 0,
minHeight = 0)) } val parentWidth = placeables.sumOf { it.width } .coerceAtMost(constraints.maxWidth) val parentHeight = placeables.maxOf { it.height } .coerceAtMost(constraints.maxHeight) return layout(parentWidth, parentHeight) { var offsetX = 0 for (placeable in placeables) { placeable.place(offsetX, 0) offsetX += placeable.width if (offsetX > parentWidth) break } } ͷ֎ʹग़ͨΒplaceऴྃ
Layout( measurePolicy = remember { SimpleRowMeasurePolicy() }, content = {
… } ) ͋ͱInstanceΛLayoutʹͤOK
༡ΜͰΈΔ
class OverlapRowMeasurePolicy(private val overlapWidth: Dp) : MeasurePolicy { override fun
MeasureScope.measure(measurables: List<Measurable>, constraints: Constraints): MeasureResult { val childConstraint = constraints.copy(minWidth = 0, minHeight = 0) val placeables = measurables.map { measurable -> measurable.measure(childConstraint) } val width = placeables.sumOf { it.width }.coerceAtMost(constraints.maxWidth) val height = placeables.maxOf { it.height }.coerceAtMost(constraints.maxHeight) return layout(width, height) { var offsetX = 0 for (placeable in placeables) { placeable.placeRelative(offsetX, 0) offsetX += (placeable.width - overlapWidth.toPx().toInt()) if (offsetX > width) break } } } } Overlap (͍ಓ͋Γͦ͏!)
class CircleMeasurePolicy : MeasurePolicy { override fun MeasureScope.measure(measurables: List<Measurable>, constraints:
Constraints): MeasureResult { val childConstraint = constraints.copy(minWidth = 0, minHeight = 0) val placeables = measurables.map { measurable -> measurable.measure(childConstraint) } val maxChildWidth = placeables.maxOf { it.width } return layout(constraints.maxWidth, constraints.maxHeight) { val radian = Math.toRadians(90.0 / placeables.lastIndex) val radius = constraints.maxWidth - maxChildWidth for (i in placeables.indices) { val x = (cos(radian * i) * radius).toInt() val y = (sin(radian * i) * radius).toInt() placeables[i].placeRelative(x, y) } } } } Circle (ҰੜΘͳͦ͏)
‣ Layout APIΛ͏ͱࢠΛࣗࡏʹஔͰ͖Δ ‣ େͷUIJetpack Composeඪ४/Accompanist͕͋ΕࣄΓΔͷ Ͱɺར༻සগͳ͍ͱࢥ͏ ‣ ߈ΊͯΔUIΛఏҊ͞Εͨ࣌ͷͨΊʹ͓͍֮͑ͯͯଛͳ͍͔ ‣
࣮؆୯͍͍͍͗͌͌͢ ·ͱΊ
Thank you