When we create an Image
view in SwiftUI, it will automatically size itself according to the dimensions of its contents. So, if the picture is 1000x500, the Image
view will also be 1000x500. This is sometimes what you want, but mostly you’ll want to show the image at a lower size, and I want to show you how that can be done, but also how we can make an image fit some amount of the user’s screen width using a relative frame.
First, add some sort of image to your project. It doesn’t matter what it is, as long as it’s wider than the screen. I called mine “Example”, but obviously you should substitute your image name in the code below.
Now let’s draw that image on the screen:
struct ContentView: View {
var body: some View {
Image("Example")
}
}
Tip: When you're using fixed image names such as this one, Xcode generates constant names for them all that you can use in place of strings. In this case, that means writing Image(.example)
, which is much safer than using a string!
Even in the preview you can see that’s way too big for the available space. Images have the same frame()
modifier as other views, so you might try to scale it down like this:
Image(.example)
.frame(width: 300, height: 300)
However, that won’t work – your image will still appear to be its full size. If you want to know why, change Xcode's preview mode from Live to Selectable – look for the three buttons at the bottom left of your Xcode preview, and click the one with a mouse cursor inside.
Important: This stops your preview from running live, so you won't be able to interact with your view until you select the Live option instead.
With Selectable mode enabled, take a close look at the preview window: you’ll see your image is full size, but there’s now a box that’s 300x300, sat in the middle. The image view’s frame has been set correctly, but the content of the image is still shown as its original size.
Try changing the image to this:
Image(.example)
.frame(width: 300, height: 300)
.clipped()
Now you’ll see things more clearly: our image view is indeed 300x300, but that’s not really what we wanted.
If you want the image contents to be resized too, we need to use the resizable()
modifier like this:
Image(.example)
.resizable()
.frame(width: 300, height: 300)
That’s better, but only just. Yes, the image is now being resized correctly, but it’s probably looking squashed. My image was not square, so it looks distorted now that it’s been resized into a square shape.
To fix this we need to ask the image to resize itself proportionally, which can be done using the scaledToFit()
and scaledToFill()
modifiers. The first of these means the entire image will fit inside the container even if that means leaving some parts of the view empty, and the second means the view will have no empty parts even if that means some of our image lies outside the container.
Try them both to see the difference for yourself. Here is .fit
mode applied:
Image(.example)
.resizable()
.scaledToFit()
.frame(width: 300, height: 300)
And here is scaledToFill()
:
Image(.example)
.resizable()
.scaledToFill()
.frame(width: 300, height: 300)
All this works great if we want fixed-sized images, but very often you want images that automatically scale up to fill more of the screen in one or both dimensions. That is, rather than hard-coding a width of 300, what you really want to say is “make this image fill 80% of the width of the screen.”
Rather than forcing a specific frame, SwiftUI has a dedicated containerRelativeFrame()
modifier that lets us get exactly the result we want. The "container" part might be the whole screen, but it might also just be the part of the screen that this view's immediate parent occupies – maybe our image is shown inside a VStack
along with other views.
We’ll go into much more detail on container relative frames in project 18, but for now we’re going to use it for one job: to make sure our image fills 80% of the available width of our screen.
For example, we could make an image that’s 80% the width of the screen:
Image(.example)
.resizable()
.scaledToFit()
.containerRelativeFrame(.horizontal) { size, axis in
size * 0.8
}
Let's break that code down:
.horizontal
because that's the one we're using, but this matters more when you create relative horizontal and vertical sizes. The size
value will be the size of our container, which for this image is the full screen.Again, we don't need to specify a height here. This is because we’ve given SwiftUI enough information that it can automatically figure out the height: it knows the original width, it knows our target width, and it knows our content mode, so it understands how the target height of the image will be proportional to the target width.
SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.
Link copied to your pasteboard.