0

When I set my pleaceable constraint as below.

LazyColumn(
    contentPadding = PaddingValues(all =64.dp),
    verticalArrangement = Arrangement.spacedBy(16.dp),
) {


    val adjust = 32.dp

    item {
        Divider(modifier = Modifier.height(20.dp))
    }
    item {
        Divider(modifier = Modifier.height(20.dp)
            .layout { measurable, constraints ->
                val placeable =
                    // -32.dp offset constraint
                    measurable.measure(constraints.offset(-adjust.roundToPx()))

                layout(placeable.width, placeable.height
                ) { placeable.place(0, 0) }
            }
        )
    }
    item {
        Divider(modifier = Modifier.height(20.dp)
            .layout { measurable, constraints ->
                val placeable =
                    // +32.dp offset constraint
                    measurable.measure(constraints.offset(adjust.roundToPx()))

                layout(placeable.width, placeable.height
                ) { placeable.place(0, 0) }
            }
        )
    }
}

The 3 rows of items result (as shown in the image) below whereby

  1. First row is the reference
  2. Second row shorted on the right side by 32.dp
  3. Third row, increase both sides by 16.dp

Why does the second and third-row behavior differs i.e. 2nd row shrink just on the right, while 3rd row expands on both side equally?

enter image description here

Elye
  • 53,639
  • 54
  • 212
  • 474
  • Second one works as expected. You measure it with width 32.dp smaller than parent, since you place at (0,0) it's placed to top left at parent. 3rd one's layout width is bigger than Constraints.maxWidth so it's centered in parent with bigger width. However this doesn't effect how other siblings are placed. If they were in a row they would both be placed as they are in bounds of Constraints. The width that overflows from parent is not taken into consideration – Thracian Jun 17 '23 at 07:59

1 Answers1

2

It's not exactly about adding or subtracting, these operations work as expected when they return values in min-max bounds of Constraints.

It's because setting layout width/height a Composable out of Constraints min-max bounds results it's being placed as the half of difference between Contraints and the value used in layout() function.

If the content chooses a size that does not satisfy the incoming Constraints, the parent layout will be reported a size coerced in the Constraints, and the position of the content will be automatically offset to be centered on the space assigned to the child by the parent layout under the assumption that Constraints were respected.

When layout width is bigger than constraints.maxWidth

(constraints.maxWidth-layout(width))/2 which means placed with offset to the left

when layout width is smaller than constraints.minWidth

(constraint.minWidth-layout(width))/2 which means placed with offset to the right.

You can refer this tutorial for more samples, information and examples about how layout, and Constraints work.

https://github.com/SmartToolFactory/Jetpack-Compose-Tutorials/blob/master/Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/chapter3_layout/Tutorial3_2_4ConstraintsBounds.kt

https://github.com/SmartToolFactory/Jetpack-Compose-Tutorials/blob/master/Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/chapter3_layout/Tutorial3_2_5SiblingConstraints.kt

https://github.com/SmartToolFactory/Jetpack-Compose-Tutorials/blob/master/Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/chapter3_layout/Tutorial3_2_6ConstrainAndOffset1.kt

Also when you change as in snippet below it will be more clear to see how it works

enter image description here

@Preview
@Composable
private fun LayoutConstraintsSample1() {
    val density = LocalDensity.current

    LazyColumn(
        modifier = Modifier
            .padding(top = 40.dp)
            .padding(horizontal = 40.dp)
            .border(1.dp, Color.Red),
        verticalArrangement = Arrangement.spacedBy(16.dp),
    ) {

        val width = with(density) {
            300f.toDp()
        }

        val adjust = 32.dp

        item {
            Divider(modifier = Modifier.height(20.dp))
        }
        item {
            Divider(modifier = Modifier
                .height(20.dp)
                .layout { measurable, constraints ->
                    val placeable =
                        // -32.dp offset constraint
                        measurable.measure(constraints.offset(-adjust.roundToPx()))

                    layout(
                        placeable.width, placeable.height
                    ) { placeable.place(0, 0) }
                }
            )
        }


        item {
            Divider(modifier = Modifier
                .width(width)
                .height(20.dp)
                .layout { measurable, constraints ->
                    val placeable =
                        measurable.measure(
                            constraints.copy(
                                minWidth = 300,
                                maxWidth = 300
                            )
                        )

                    layout(
                        200, placeable.height
                    ) { placeable.place(0, 0) }
                }
            )
        }

        item {
            Divider(modifier = Modifier
                .width(width)
                .height(20.dp)
                .layout { measurable, constraints ->
                    val placeable =
                        measurable.measure(
                            constraints.copy(
                                minWidth = 300,
                                maxWidth = 300
                            )
                        )

                    layout(
                        400, placeable.height
                    ) { placeable.place(0, 0) }
                }
            )
        }
    }
}

Placable width is same(300px) for both instances

enter image description here

@Preview
@Composable
private fun LayoutConstraintsSample2() {
    val density = LocalDensity.current

    LazyColumn(
        modifier = Modifier
            .padding(top = 40.dp)
            .padding(horizontal = 40.dp)
            .border(1.dp, Color.Red),
        verticalArrangement = Arrangement.spacedBy(16.dp),
    ) {

        val width = with(density) {
            300f.toDp()
        }

        val adjust = 32.dp

        item {
            Divider(modifier = Modifier.height(20.dp))
        }
        item {
            Divider(modifier = Modifier
                .height(20.dp)
                .layout { measurable, constraints ->
                    val placeable =
                        // -32.dp offset constraint
                        measurable.measure(constraints.offset(-adjust.roundToPx()))

                    layout(
                        placeable.width, placeable.height
                    ) { placeable.place(0, 0) }
                }
            )
        }


        item {
            Divider(modifier = Modifier
                .width(width)
                .height(20.dp)
                .layout { measurable, constraints ->
                    val placeable =
                        measurable.measure(
                            constraints.copy(
                                minWidth = 300,
                                maxWidth = 300
                            )
                        )

                    layout(
                        200, placeable.height
                    ) { placeable.place(0, 0) }
                }
            )
        }

        item {
            Divider(modifier = Modifier
                .width(width)
                .height(20.dp)
                .layout { measurable, constraints ->
                    val placeable =
                        measurable.measure(
                            constraints.copy(
                                minWidth = 300,
                                maxWidth = 300
                            )
                        )

                    layout(
                        400, placeable.height
                    ) { placeable.place(0, 0) }
                }
            )
        }
    }
}
Thracian
  • 43,021
  • 16
  • 133
  • 222
  • 1
    You can also refere Modifier.requiredWidth in this answer which results as in the answer when reuqiredWidth is bigger than Modifer.size before it. https://stackoverflow.com/a/73316247/5457853 – Thracian Jun 16 '23 at 15:12