markusp
markusp

Reputation: 419

How can I make an image 100 percent the width of its container in SwiftUI?

I have users uploading images from their mobile device and these images can be either are portrait or landscape. I have these images tiled similar to Instagram posts. The biggest problem I'm having is that portrait images are not rendering at 100 percent of the container width. It's really bizarre.

Here is an example of a "portrait" photo taken by me and visualized using the following code:

VStack{
    AnimatedImage(url: URL(string: self.mediaLink))
        .resizable()
        .aspectRatio(contentMode: .fit)
        .frame(width: UIScreen.main.bounds.width - 40)
}
.padding(.horizontal, 20)
.frame(width: UIScreen.main.bounds.width - 40)

Even though I am specifying the width, it still renders incorrectly. It should be UIScreen.main.bounds.width - 40, which is the same width as its parent VStack

enter image description here

When using GeometryReader, my code looks like this:

GeometryReader{geo in
    VStack{
        AnimatedImage(url: URL(string: self.mediaLink))
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: geo.size.width)
    }
}
.frame(width: UIScreen.main.bounds.width)

Which is worse!

enter image description here

Any help is appreciated! Using .fill for the aspect ratio makes the images too large and they block everything in the card. The below code does not use GeometryReader

VStack{
    AnimatedImage(url: URL(string: self.mediaLink))
        .resizable()
        .aspectRatio(contentMode: .fill)
        .frame(width: UIScreen.main.bounds.width - 40)
}
.frame(width: UIScreen.main.bounds.width - 40)

enter image description here

Upvotes: 8

Views: 3504

Answers (4)

Bill
Bill

Reputation: 45465

All of these answers use UIScreen.main.bounds.width, which is a bad idea.

What if the view is in a form sheet, or used inside a sidebar layout on the iPad? What if the size of the container changes after you set it up? Using a fixed numeric size like that is going to cause problems.

Instead, use the containerRelativeFrame modifier:

      Image("some_image")
        .resizable()
        .scaledToFit()
        .containerRelativeFrame(.horizontal)  { width, axis in
          width
        }

This will set the width of the image to the exact width of its container, and will even update as the container's size changes.

This requires iOS 17, but even if you have to support older versions, you can use GeometryReader to achieve the same thing with a little more boilerplate.

Upvotes: 0

Asperi
Asperi

Reputation: 258461

Tested your code with just Image("some_image") as below and it works (Xcode 12 / iOS 14), so the issue is either in AnimatedImage or in some other code.

VStack{
    Image("some_image")
        .resizable()
        .aspectRatio(contentMode: .fit)
        .frame(width: UIScreen.main.bounds.width - 40)
}
.padding(.horizontal, 20)
.frame(width: UIScreen.main.bounds.width - 40)

Upvotes: 5

Anton Shpakowski
Anton Shpakowski

Reputation: 31

Try to use scaledToFill and clipped modifiers

    VStack{
        AnimatedImage(url: URL(string: self.mediaLink))
            .resizable()
            .scaledToFill()
            .frame(width: UIScreen.main.bounds.width - 40)
            .clipped()
    }
    .frame(width: UIScreen.main.bounds.width - 40)

Upvotes: 1

Phạm Đông
Phạm Đông

Reputation: 9

I think this change will help you:

VStack {
    AnimatedImage(url: URL(string: self.mediaLink))
       .resizable()
       .scaledToFit()
}
.frame(width: UIScreen.main.bounds.width - 40)

Upvotes: 0

Related Questions