I am trying to display a list of images from panoramic webcams with following display constraints:
- rounded corners
- 16/9 aspect ratio
- center crop scale type (image is centered and cropped to fill available space while maintaining its own aspect ratio)
following what I achieved in my Android app while still learning SwiftUI:
AsyncImage( // from Coil library
model = webcam.illustrationImageUrl,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.aspectRatio(16 / 9f)
.hazeSource(state = hazeState),
)
I tried using a combination of resizable, scaledToFill, aspectRatio, clipped followed by either clipToShape or background, but to no avail.
For instance, this code:
AsyncImage(url: URL(string: webcam.illustrationImageUrl)) { image in
image
.resizable()
.scaledToFill()
.aspectRatio(16 / 9, contentMode: .fit)
.clipped()
.clipShape(.rect(cornerRadius: 16))
} placeholder: {
ProgressView()
}
will results in this:
Clearly my rounding corners are in a mess:
- First image: no rounded corners
- Second image: clipped rounded corners
- Third image: fully rounded corners
My understanding is as follow: shape clipping seems to apply to the source image and not to what is actually visible (after scaling / cropping) or, the View (image container) itself.
Why? Because the second image shows a bit of its original corners, which results in slightly rounded corners while the second image does not display its original corner due to a much larger width with much content left and right out of the visual bounds. And if you take the last image, it is properly rounded, because it is displayed entirely!
I also tried switching from scaledToFill to scaledToFit: all images are properly rounded because they are now entirely displayed. But due to their varying dimensions and original aspect ratio, none respect my 16/9 aspect ratio constraint:
Finally, I also tried wrapping the AsyncImage and even its underlying Image in a ZStack to which I tried both clipToShape and containerShape, but it does not change anything at all.
Why can’t I achieve the desired result? Thanks for the help!



