How on earth do you reason about order of Jetpack Compose modifiers?

420 Views Asked by At

I get that Jetpack Compose operates from the outside in for modifiers, but what about this one?

What I asked for:

  • 8 dp padding
  • then 2 dp border
  • then background colour for component
  • then 16 dp padding
@Composable
fun App() {
    MaterialTheme(colors = darkColors()) {
        Surface(
            modifier = Modifier
                .background(MaterialTheme.colors.background)
                .fillMaxSize()
                .padding(8.dp)
        ) {
            Column {
                Card(
                    modifier = Modifier
                        .requiredSize(DpSize(300.dp, 200.dp))
                        .border(BorderStroke(2.dp, Color.White), RoundedCornerShape(8.dp))
                        .background(MaterialTheme.colors.surface)
                        .padding(16.dp)
                ) {
                    // Content still to come
                }
            }
        }
    }
}

What I got:

  • 8 dp padding
  • then 2 dp border
  • --then 16 dp padding--
  • --then background colour for component--

screenshot

How do I reason about the background colour not extending to the border here? I defined it immediately after.

Addendum:

By the way, swap border and background - same result:

screenshot

1

There are 1 best solutions below

2
On

Modifier order has always been confusing, but they have a rule: they will append each other since a modifier extension returns a modifer.then. The closest and probably the best incongruity and analogy:

  • properties are not applied to a view collectively, forget css and xml styling
  • properties are sequenced, like factory workers on a production line, if padding is first, the next border call will be inside the padding. If border is first, padding will be inside the border

So be careful of positional modifiers.