7

I would like to display an image with the following rules:

  • The image is remote and needs to load on runtime.
  • We don't know what the image size is until it's loaded.
  • The Image view should take the full width of the parent, and it should automatically adjust its height to match the remotely loaded image, so that no cropping/stretching occurs.

I tried using the Coil dependency and I have this code:

Image(
    painter = rememberImagePainter(viewModel.fullImageUrl),
    contentDescription = null,
    contentScale = ContentScale.FillHeight,
    modifier = Modifier
        .fillMaxWidth()
        .aspectRatio(3.21428f) // TODO: Figure out how to set height/ratio based on image itself
)

When I remove the Image's contentScale and modifier, its height always seems to be zero. I'm not sure what I should do to make Image fill the max width of its parent while determining its own size after Coil loads the image file.

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
Eugene
  • 3,417
  • 5
  • 25
  • 49

1 Answers1

19

As you set flexible width with fillMaxWidth, you need to use ContentScale.FillWidth for your contentScale:

Image(
    painter = rememberImagePainter(
        "https://via.placeholder.com/300.png",
    ),
    contentDescription = null,
    contentScale = ContentScale.FillWidth,
    modifier = Modifier
        .fillMaxWidth()
)

The following will work fine if your image has enough priority. But in some cases coil won't start loading because it's gonna think that image is zero size so no need to display it. For such case you can add size(OriginalSize) parameter to the builder:

rememberImagePainter(
    "https://via.placeholder.com/300.png",
    builder = {
        size(OriginalSize)
    }
)

This parameter makes your view download and put into the memory full size of the image, without optimizing it for the current view. So use it carefully, only if you're sure the image won't be too big and you really can't add use size modifiers.


If image is getting loaded but still not takes enough space, you can set aspect ratio like this:

val painter = rememberImagePainter("https://via.placeholder.com/300.png")
Image(
    painter = painter,
    contentDescription = null,
    contentScale = ContentScale.Fit,
    modifier = Modifier
        .fillMaxWidth()
        .then(
            (painter.state as? ImagePainter.State.Success)
                ?.painter
                ?.intrinsicSize
                ?.let { intrinsicSize ->
                    Modifier.aspectRatio(intrinsicSize.width / intrinsicSize.height)
                } ?: Modifier
        )
)

If none of these helped and painter.state is not changing from Empty, try hardcode height ?: Modifier.height(10.dp) to let image start loading

Johann
  • 27,536
  • 39
  • 165
  • 279
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
  • 2
    @Eugene looks like you haven't tried my latest suggestion with `builder = { size(OriginalSize) }`, this works for you example – Phil Dukhov Aug 19 '21 at 18:55
  • This solution also worked for me. Please keep in mind that it should be considered as temporary solution. This parameter makes your view download and put into the memory full size of the image, without optimizing it for the current view So use it carefully, only if you're sure the image won't be too big and you really can't add use size modifiers. – Serhii Tereshchenko Oct 06 '21 at 14:47
  • @SerhiiTereshchenko Thanks for that clarification, I added that information to my response. – Phil Dukhov Oct 07 '21 at 06:51
  • ContentScale.FillWidth reduces height of the image as well. – Sarojini2064130 Feb 01 '22 at 15:26