MyFamilyTracker
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
When Row, Column, and Box can't express your design, Compose's Layout composable and custom modifiers let you measure and place children yourself. Here's how the measure-and-place model works and when to reach for it.
On this page
Most Compose UI is built from
RowColumnBoxLayoutEvery Compose layout follows the same two-phase contract: measure each child, then place it. The parent hands each child constraints, the child reports its size, and the parent decides where to put it. The
Layout@Composable
fun MyLayout(content: @Composable () -> Unit) {
Layout(content) { measurables, constraints ->
val placeables = measurables.map { it.measure(constraints) }
val height = placeables.maxOf { it.height }
layout(constraints.maxWidth, height) {
var x = 0
placeables.forEach { it.placeRelative(x, 0); x += it.width }
}
}
}That's the whole shape: measure children into placeables, compute your own size, then position each placeable in the placement block. Once this clicks, custom layouts stop being mysterious — they're just your own rules for two steps you already understand.
The one hard rule of the measure phase: each child is measured exactly once. Compose's single-pass layout is what keeps it fast, and measuring a child twice throws. This is a deliberate constraint — it forces layouts to be efficient by construction. If you find yourself wanting to measure twice to "see how big something is first," that's a sign to rethink the approach, often using intrinsic measurements instead.
Not every customization needs a full layout. Often you just want to tweak how a single composable is sized or positioned, and that's a custom modifier. A
layoutfun Modifier.offsetUp(by: Dp) = layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
layout(placeable.width, placeable.height) {
placeable.place(0, -by.roundToPx())
}
}Custom modifiers are the lighter-weight tool, and I reach for them far more often than full custom layouts because most needs are about one element, not an arrangement of many.
Sometimes a parent genuinely needs to know a child's natural size before deciding its own — making all items as tall as the tallest, for instance. Intrinsic measurements provide this without breaking the single-measure rule: they let the parent query a child's preferred width or height in a separate, cheap pass. It's the sanctioned escape hatch for the "I need to know the size first" situation, and reaching for it is cleaner than fighting the single-pass model.
The deep-dive caveat: custom layouts are powerful and almost always unnecessary. The built-in layouts plus modifiers like
weightalignoffsetLayoutWhat I find reassuring about custom layouts is that the model is genuinely small once you stop being intimidated by it. There's no sprawling API to memorize — there's measure, there's place, and there's the single-pass rule that keeps it honest. Everything else is just your own arithmetic about where things go. The first time you write one it feels like dropping into the engine room; the third time it feels like ordinary Compose code, because that's what it is. So the right attitude is neither fear nor eagerness: don't avoid custom layouts when the design truly needs them, and don't reach for them when
RowLayoutlayoutSudarshan Chaudhari
AI Systems Builder / Product Engineer
Bangkok, Thailand
Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.
Related Posts
Related Apps
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
Building something? Available for Android dev and QA consulting.
Work with meComments — powered by Giscus
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
ReadPrivate dream journal — structured entry capture, pattern tagging, and optional Claude-powered insight generation. All data stays on-device by default.
ReadWorkout tracker — exercise logging with set/rep/weight history, goal progression, and local Room DB persistence. No account, no cloud sync required.
Read