Skip to content
All posts
July 29, 20264 min read

Jetpack Compose Custom Layouts and Modifiers Deep Dive

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.

Jetpack ComposeCustom LayoutAndroidUIKotlin
Share:

Most Compose UI is built from

code
Row
,
code
Column
, and
code
Box
, and that's exactly as it should be — they cover the vast majority of layouts cleanly. But occasionally a design needs something they can't express: a flow layout that wraps chips, a custom arrangement that positions children by your own rules. That's when you drop down to the
code
Layout
composable and do the measuring and placing yourself. It sounds intimidating; the model is actually small.

The Measure-Place Model

Every 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

code
Layout
composable exposes exactly this.

kotlin
@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.

Measure Children Exactly Once

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.

Custom Modifiers for Reusable Behavior

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

code
layout
modifier lets you adjust one element's measurement and placement without writing a whole parent layout.

kotlin
fun 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.

Use Intrinsics When You Need Sizing Hints

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.

Don't Reach for This Too Early

The deep-dive caveat: custom layouts are powerful and almost always unnecessary. The built-in layouts plus modifiers like

code
weight
,
code
align
, and
code
offset
express far more than people assume, and a custom
code
Layout
is more code to write, test, and maintain. I only drop to it when I've confirmed the standard tools genuinely can't do the job — a true flow-wrap, a radial arrangement, a chart axis. Reaching for a custom layout because you haven't fully explored the standard ones is exactly the kind of premature complexity worth avoiding. When you do need it, the measure-place model is clean and learnable; just make sure you actually need it first.

What 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

code
Row
and a modifier would do. Match the tool to the actual requirement and the measure-place model is a friendly, learnable corner of the framework rather than a scary one.

Key Takeaways

  • Every Compose layout measures children then places them; the
    code
    Layout
    composable exposes that two-phase contract directly.
  • Measure each child exactly once — the single-pass rule is what keeps layout fast, and double-measuring throws.
  • Use a custom
    code
    layout
    modifier for tweaking a single element; it's lighter than a full custom layout and more commonly what you need.
  • Reach for intrinsic measurements when a parent legitimately needs a child's natural size before sizing itself.
  • Exhaust the built-in layouts and modifiers first; custom layouts are powerful but usually premature complexity.
Share:
S

Sudarshan 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.

Stay updated

Get new posts on Android, Kotlin, and solo dev straight to your inbox.

Newsletter preferences

Related Apps

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.

Building something? Available for Android dev and QA consulting.

Work with me

Comments — powered by Giscus

Apps tagged with this