Home > Back-end >  Why are the modifier sizes not overwritten?
Why are the modifier sizes not overwritten?

Time:03-31

I have a composable function it assigns a size to a surface.

@Composable
private fun CreateImage(modifier: Modifier = Modifier) {
    Surface(
        modifier = modifier
            .size(150.dp)
            .padding(5.dp),
        shape = CircleShape,
        border = BorderStroke(1.dp, Color.LightGray)
    ) {
        Image(
            painter = painterResource(id = R.drawable.profile_image),
            contentDescription = "Profile Image",
            contentScale = ContentScale.Crop
        )
    }
}

When I call another method and change the size in the modifier parameter shouldn't it stick to 150dp.

If I call this method:

@Composable
private fun ChangeSize(name: String) {
    CreateImage(Modifier.size(100.dp))
}

It stays with the size 100dp even though in CreateImage I set it to 150dp. Why is the size not changing to 150dp and staying 100dp?

I thought it was supposed to change it to 150dp. Why is that not the case?

CodePudding user response:

Modifier uses first size it got and it's a great feature when people don't provide any size to your Composable.

For instance

  CircleDisplay(
        modifier = circleModifier
            .widthIn(min = 70.dp)
            .heightIn(min = 70.dp),
        color = color
    )

if anyone doesn't provide any Modifier with any width or height instead of having 0 height and width you give a minimum size to your Composable. You can change this to max or exact size depending on your implementation. But when user modifier has some width height instead of yours the one provided by them is used thanks to using first size.

Default Composables like Slider also use this pattern, so without setting any dimension it has 48.dp height and fills max width of its parent.

BoxWithConstraint under Slider is as

    BoxWithConstraints(
        modifier
            .minimumTouchTargetSize()
            .requiredSizeIn(minWidth = ThumbRadius * 2, minHeight = ThumbRadius * 2)
            .sliderSemantics(value, tickFractions, enabled, onValueChange, valueRange, steps)
            .focusable(enabled, interactionSource)
    ) {
     // Rest of the Slider Implementation

}

CodePudding user response:

The reason why your composable will always have a size of 150.dp is because of how modifiers are applied. When modifiers are chained onto a composable, they are applied sequentially from top to bottom until the last modifier is applied. This can be demonstrated with a very simple Box composable

@Composable 
fun Screen(){
  Box(
      modifier = Modifier
                  .size(100.dp)
                  .background(color = Color.Yellow)
                  .background(color = Color.Green)
                  .background(color = Color.Red)
  )

In this simple Box composable, the rendered color will be Color.Red because it will be the last color applied before it gets drawn onto the screen.

A similar thing is happening in your example above. Even though you are calling your composable with a modifier of 100.dp, the final size that get's applied is 150.dp because your modifier with 100.dp get's applied too early in the modifier chain.

Replace your composable with this one and it should work as expected

@Composable
private fun CreateImage(modifier: Modifier = Modifier) {
    Surface(
        modifier = Modifier
            .size(150.dp)
            .padding(5.dp)
            .then(modifier), //this last modifier will override everything above
        shape = CircleShape,
        border = BorderStroke(1.dp, Color.LightGray)
    ) {
        Image(
            painter = painterResource(id = R.drawable.profile_image),
            contentDescription = "Profile Image",
            contentScale = ContentScale.Crop
        )
    }
}
  • Related