Ruben Veldman
Ruben Veldman

Reputation: 640

How to make divider ignore padding of parent in Jetpack Compose?

I am trying to create a layout in which the parent of the content has horizontal padding, but the divider between content items should ignore the padding on the right side.

To make it more clear, I made this drawing of what I want: drawing of layout that uses divider that ignores padding of parent

Now, I got something to work by using the Modifier.offset(x=16.dp) and that did the trick except that now the divider is now too 'short' on the left side, like this: drawing of layout that ignores the padding but left side is too shortHow can I achieve such a layout? Thanks in advance!

Upvotes: 12

Views: 7738

Answers (3)

Mikalai Parafeniuk
Mikalai Parafeniuk

Reputation: 1366

I would suggest to slightly amend the solution from Oya to use this.layout {} instead of this.then(layout {}):

fun Modifier.fillWidthOfParent(parentPadding: Dp) = this.layout { measurable, constraints ->
  // This is to force layout to go beyond the borders of its parent
  val placeable =
    measurable.measure(constraints.copy(maxWidth = constraints.maxWidth + 2 * parentPadding.roundToPx()))
  layout(placeable.width, placeable.height) {
    placeable.place(0, 0)
  }
}

Why?

In the original solution fillWidthOfParent would call previous modifiers in chain twice. Commenting fillWidthOfParent using this.then(layout {}) in the following reproducer will add additional vertical padding:

@Composable
@Preview(widthDp = 60, heightDp = 100)
fun TestPreview() {
  Column(
    modifier = Modifier
      .background(Color.Gray)
      .padding(10.dp)
  ) {
    Text(
      modifier = Modifier
        .background(Color.Cyan)
        .padding(bottom = 20.dp)
        .fillWidthOfParent(10.dp) // Try commenting and uncommenting this line
      ,
      text = "xxxxxxxxxx"
    )
  }
}
Without fillWidthOfParent fillWidthOfParent with this.layout {} fillWidthOfParent with this.then(layout {})
Preview result Preview result Preview result

Upvotes: 2

Oya Canli
Oya Canli

Reputation: 2516

We have a few components in our grid that needs to go full width. Based on Gabriele's answer, I made this a reusable custom modifier:

fun Modifier.fillWidthOfParent(parentPadding: Dp) = this.then(
  layout { measurable, constraints ->
    // This is to force layout to go beyond the borders of its parent
    val placeable = measurable.measure(
        constraints.copy(
            maxWidth = constraints.maxWidth + 2 * parentPadding.roundToPx(),
        ),
    )
    layout(placeable.width, placeable.height) {
        placeable.place(0, 0)
    }
  },
)

When I want a component to bypass parent's padding and go full screen, I pass this modifier instead of fillMaxWidth(). The argument passed is the padding of the parent. You can assign it a default value if your app screen has consistent page margins (which is hopefully the case)

Upvotes: 13

Gabriele Mariotti
Gabriele Mariotti

Reputation: 364506

The offset modifier doesn't work because you are just applying an offset without changing the width.
You can use the layout modifier to specify the size and the position where the element should be placed.

Something like:

   Divider(
       color = Black,
       modifier = Modifier
        .layout(){ measurable, constraints ->
            val placeable = measurable.measure(constraints.copy(
                maxWidth = constraints.maxWidth + 16.dp.roundToPx(), //add the end padding 16.dp
            ))
            layout(placeable.width, placeable.height) {
                placeable.place(8.dp.roundToPx(), 0) 
            }
      }
   )

enter image description here

Upvotes: 19

Related Questions