2

Recently, I try to migrate to Jetpack compose.

So, I want to show 'card' where has 'indicator' while loading but I can't change 'indicator' size in 'SubcomposeAsyncImage'

@Composable
private fun SponsorDialogContent(
    imgUrl: String,
) {
    Card(
        modifier = Modifier
            .width(300.dp)
            .wrapContentHeight(),
        elevation = CardDefaults.cardElevation(0.dp),
        shape = RoundedCornerShape(10.dp)
    ) {
        Box() {
            SubcomposeAsyncImage(
                modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentHeight()
                    .heightIn(min = 200.dp),
                model = imgUrl,
                contentDescription = null,
                loading = {
                    CircularProgressIndicator(modifier = Modifier.size(30.dp).align(Alignment.Center), progress = 1f)
                },
                alignment = Alignment.Center,
                contentScale = ContentScale.FillWidth
            )

            CircularProgressIndicator(1f, Modifier.width(30.dp).align(Alignment.Center))
        }
    }
}

So. I have try the code below

@Composable
private fun SponsorDialogContent(
    imgUrl: String,
) {
    Card(
        modifier = Modifier
            .width(300.dp)
            .wrapContentHeight(),
        elevation = CardDefaults.cardElevation(0.dp),
        shape = RoundedCornerShape(10.dp)
    ) {
        Box() {
            SubcomposeAsyncImage(
                modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentHeight()
                    .heightIn(min = 200.dp),
                model = imgUrl,
                contentDescription = null,
                loading = {
                    Box(contentAlignment = Alignment.Center) {
                        CircularProgressIndicator()
                    }
                },
                alignment = Alignment.Center,
                contentScale = ContentScale.FillWidth
            )
        }
    }
}

Then, works well, but I don't know why Does anyone know why?

I tried to find how to work this code but failed

enter image description here

Goodham
  • 57
  • 7

2 Answers2

4

If you browse the source code of SubcomposeAsyncImage, you will get to the point where you can see this:

BoxWithConstraints(
    modifier = modifier, // this is the modifier you passed to SubcomposeAsyncImage
    contentAlignment = alignment,
    propagateMinConstraints = true,
) {
    // image or your loading content based on state
}

So the behavior you describe is because of your modifier that has heightIn(min = 200.dp) and your progress indicator that ends up being direct child of this Box which has propagateMinConstraints = true.

Jan Bína
  • 3,447
  • 14
  • 16
4

As @Jan Bina mentioned it has propagateMinConstraints = true which means it forces minimum constraints to its direct child only. I explained in this answer how it effects with Surface because Surface is a Box with propagateMinConstraints = true. You can try out these with Box and you will see the same outcomes

Surface(
    modifier = Modifier.size(200.dp),
    onClick = {}) {
    Column(
        modifier = Modifier
            .size(50.dp)
            .background(Color.Red, RoundedCornerShape(6.dp))
    ) {}
}

Spacer(modifier = Modifier.height(20.dp))

Surface(
    modifier = Modifier.size(200.dp),
    onClick = {}) {
    Column(
        modifier = Modifier
            .size(50.dp)
            .background(Color.Red, RoundedCornerShape(6.dp))
    ) {
        Column(
            modifier = Modifier
                .size(50.dp)
                .background(Color.Green, RoundedCornerShape(6.dp))
        ) {}

    }
}

Spacer(modifier = Modifier.height(20.dp))

Box(
    modifier = Modifier.size(200.dp)
) {
    Column(
        modifier = Modifier
            .size(50.dp)
            .background(Color.Red, RoundedCornerShape(6.dp))
    ) {
        Column(
            modifier = Modifier
                .size(50.dp)
                .background(Color.Green, RoundedCornerShape(6.dp))
        ) {}

    }
}

enter image description here

In first example on Surface forces Column to have 200.dp size even though it has Modifier.size(50.dp).

In second example Box inside Column has 50.dp size because it's not a direct descendant of Surface.

In third example if we replace Surface(Box with propagateMinConstraints true) with Box it allows direct descendant to use its own constraints or dimensions.

And when you set Modifier.fillMaxWidth you set Constraints as minWidth = parent width, maxWidth = parentWidth

I answered about Constraint types here

enter image description here

Thracian
  • 43,021
  • 16
  • 133
  • 222