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
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
290
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
380
RecycledViewPool
lvla
1
290
CameraX
lvla
2
2.5k
Other Decks in Programming
See All in Programming
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.3k
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
210
Oxcを導入して開発体験が向上した話
yug1224
4
340
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
970
エンジニア向け会社紹介/Findy Company Profile
findyinc
6
350k
フロントエンドとバックエンドで「1文字」を揃えよう
youkidearitai
PRO
0
750
ランチタイムLT会3周年!ランチタイムLT会を3年間続けられたお話
y0hgi
1
110
任せる範囲はこう広がった / How the Scope of AI Delegation Has Expanded
nrslib
0
160
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
600
決定論的オーケストレーションの設計と実装 / Design and Implementation of Deterministic Orchestration
nrslib
4
1.5k
TypeScript+Orvalで実現する型安全かつ堅牢でスケーラブルなマルチチャネル通知基盤 / TSKaigi Night talks ~after conference~
d0riven
0
360
鹿野さんに聞く!『TypeScriptコードレシピ集』で磨く実践力
tonkotsuboy_com
4
860
Featured
See All Featured
Facilitating Awesome Meetings
lara
57
7k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
170
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
370
Heart Work Chapter 1 - Part 1
lfama
PRO
8
36k
The browser strikes back
jonoalderson
0
1.3k
Building AI with AI
inesmontani
PRO
1
1.1k
RailsConf 2023
tenderlove
30
1.5k
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
450
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
65
56k
KATA
mclloyd
PRO
35
15k
Producing Creativity
orderedlist
PRO
348
40k
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