How to resize image and keep aspect ratio in SwiftUI

Dec 03, 2023#swiftui#images

The default behavior of Image in SwiftUI is to render the content in its true size, regardless of the frame it gets offered by the parent view. This means that the image may not fit the available space, and may overflow or leave empty space around it.

To change this behavior, you can apply various modifiers to the image view, such as .resizable(), .aspectRatio(contentMode:), .scaledToFit(), .scaledToFill(), .frame(width:height:), .clipped(). These modifiers allow you to resize, scale, crop, or align the image to fit the desired size and shape.

Resize Image in SwiftUI

One of the most common methods is to use the .aspectRatio(contentMode:) modifier on the image view, which accepts either .fit or .fill as the content mode.

  • The .fit mode scales the image to fit the available space along one axis, possibly leaving empty space along the other axis. This preserves the image’s original aspect ratio and ensures that the entire image is visible.
  • The .fill mode scales the image to fill the entire space, possibly cropping some parts of the image. This also preserves the image’s original aspect ratio, but may not show the whole image.
Image("example")
  .resizable()
  .aspectRatio(contentMode: .fit) // or .fill

You can also use the .scaledToFit() or .scaledToFill() modifiers, which are equivalent to .aspectRatio(contentMode: .fit) or .aspectRatio(contentMode: .fill), respectively.

Image("example")
  .resizable()
  .scaledToFit() // or .scaledToFill()

Another method is to use the .frame(width:height:) modifier to specify the desired size of the image view, and then use the .clipped() modifier to clip the image to the bounds of the view. For example:

Image("example")
  .resizable()
  .frame(width: 200, height: 200)
  .clipped()

This method will also crop some parts of the image if the aspect ratio of the frame does not match the aspect ratio of the image.

Resize AsyncImage in SwiftUI

To resize an AsyncImage and keep its aspect ratio in SwiftUI, you can use the same modifiers as you would use for a regular Image view.

AsyncImage(url: URL(string: "https://example.com/image.png")) { image in
  image.resizable()
    .aspectRatio(contentMode: .fit) // or .fill
} placeholder: {
  ProgressView()
}

This will display an image downloaded from the URL, with a ProgressView as a placeholder until the image loads. The image will be resized to fit or fill the available space, while preserving its aspect ratio. You can also use the .frame(width:height:) modifier to specify the desired size of the AsyncImage view, and then use the .clipped() modifier to clip the image to the bounds of the view.

AsyncImage(url: URL(string: "https://example.com/image.png")) { image in
  image.resizable()
    .frame(width: 200, height: 200)
    .clipped()
} placeholder: {
  ProgressView()
}

This will display an image with a fixed size of 200x200 points, and clip any parts of the image that go beyond the view’s bounds.