Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Jetpack Compose Layout API
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Moyuru Aizawa
February 17, 2023
Programming
710
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
410
Jetpack Composeで画像クロップ機能を実装する
lvla
0
1.3k
Jetpack Compose drag gesture and pinch gesture
lvla
1
4.3k
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
Built Our Own Background Agent at LayerX
layerx
PRO
9
5.1k
関東Kaggler会_NVIDIA_Nemotron_コンペ_振り返り
rick_ds
0
490
数百円から始めるRuby電子工作
tarosay
0
140
生成AI導入の「期待外れ」を乗り越える ー 開発フロー改革が目指す、真の組織変革
starfish719
0
4.1k
GDG Korea Android: 2026 I/O Extended ~ What's new in Android development tools
pluu
0
220
Apache Hive: そしてCloud Native Lakehouseへ
okumin
1
210
Foundation Models frameworkで画像分析
ryodeveloper
1
600
AI時代のPHPer生存戦略 ~「言語、もうなんでもよくない?」に本気で向き合う~
vivion
0
300
プロポーザルを書いてもらう
pvcresin
0
290
Go言語とトイモデルで学ぶTransformerの気持ち / fukuokago23-transformer
monochromegane
0
160
テーブルをDELETEした
yuzneri
0
140
ビデオ通話が繋がる0.2秒で何が起きているのか
supurazako
2
180
Featured
See All Featured
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
790
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
200
Odyssey Design
rkendrick25
PRO
2
750
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
930
Large-scale JavaScript Application Architecture
addyosmani
515
110k
How STYLIGHT went responsive
nonsquared
100
6.2k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
Building AI with AI
inesmontani
PRO
1
1.1k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
450
WCS-LA-2024
lcolladotor
0
790
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
790
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