androidiconsandroid-jetpack-composemodifiercomposable

decrease size of icon in jetpack compose to match row height


I have the following composable.

@Composable
fun Temp() {
    Row(
        modifier = Modifier
            .background(Color.Red)
            .height(IntrinsicSize.Min)
            .fillMaxWidth()
    ) {
        Text(text = "Hello", fontSize = 10.sp)
        Icon(
            imageVector = Icons.Default.Star,
            contentDescription = "Star",
            modifier = Modifier.fillMaxHeight()
        )
    }
}

The height of icon is not decreasing from 24.dp. Is there any way I can achieve this behavior. I want the icon size to just be the height of the parent row. If the text is large. The icons size is increased. I think it has to be with icon minimum size being 24.dp. How can I make icon smaller?


Solution

  • Your code actually works as expected - that's how intrinsic calculations work.

    Compose checks the min height of each view and chooses the maximum of those values. In your case, the min height of the image is related to the intrinsic size of the image, which you cannot control in the case of Icons.Default.

    A possible solution is to use Modifier.layout. When Compose calculates the intrinsic height, the height constraint will be infinite, in which case you can layout it as a zero size view, so that your text will be the highest. When the intrinsic height is determined, you can measure and position the icon:

    Row(
        modifier = Modifier
            .background(Color.Red)
            .height(IntrinsicSize.Min)
            .fillMaxWidth()
    ) {
        Text(text = "Hello", fontSize = 10.sp)
        Icon(
            imageVector = Icons.Default.Star,
            contentDescription = null,
            modifier = Modifier
                .layout { measurable, constraints ->
                    if (constraints.maxHeight == Constraints.Infinity) {
                        layout(0, 0) {}
                    } else {
                        val placeable = measurable.measure(constraints)
                        layout(placeable.width, placeable.height) {
                            placeable.place(0, 0)
                        }
                    }
                }
        )
    }
    

    Using Modifier.layout you can change size of view and its position. Usually you use it like this:

    1. First parameter, measurable is an object on which you can call measure with constraints - the second layout parameter. measure is gonna calculate the size your view will take, taking constraints in count.
    2. in layout you need to pass the desired view size - usually it can be taken from placeable from the previous step.
    3. inside layout you need to call place on the placeable with the desired offset.

    With height(IntrinsicSize.Min) layout content is getting called multiple times:

    1. during the first call(s) max height constraint is equal to Infinity, so intrinsic calculations can select the correct size ignoring the parent size.
    2. In the last call max height constraint is equal to the calculated parent intrinsic height.

    In my code during first calls, when height constraint is equal to Infinity, I say that this view has zero size, so it's not counted in intrinsic measurements. When intrinsic height is defined, I can layout it with the final constraints.