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 × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
160
自分的「カンファレンスの楽しみ方」
syumai
0
200
巨大モノリシックアプリ モダン化大作戦
ktcryomm
0
1k
Java 27新機能 / Java 27 new features
kishida
2
130
Go のフラットな パッケージに 「ファイル単位の private」を 〜Linter “declscope” を作った話〜
mpyw
0
310
AGENTS.md Is Not Enough:Build Skills, Don't Download Them
lx_t
0
120
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
200
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
350
kubernetes コンポーネント開発入門 / 新卒N年目の勉強会&交流会!〜〇〇への誘い〜 #n_study
mazrean
0
240
型解析で実現する Go の言語内 DSL / Conference に Go! タイムテーブルの歩き方 for Gophers
mazrean
0
150
Jetpack Compose メカニズム
skydoves
0
410
AI に Inclusive UI を書かせよう — Design Rules Skill で Compose UI を作り直す
theoriatec2024
1
490
Featured
See All Featured
The agentic SEO stack - context over prompts
schlessera
0
940
Ruling the World: When Life Gets Gamed
codingconduct
0
330
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
540
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.4k
Into the Great Unknown - MozCon
thekraken
41
2.7k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
300
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
240
Building an army of robots
kneath
307
46k
Claude Code のすすめ
schroneko
67
230k
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
560
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