SwiftUI Field Guide

Aspect Ratio

The most common usage of aspect ratio is in combination with a resizable image, as shown below. The modifier ensures sure that the image always maintains the correct aspect ratio while resizing. Note that using fill as the content mode will draw the image out of bounds.

Code
Image("mountains")    .resizable()    .aspectRatio(contentMode: .fit)
Preview
FitFill
200

The aspect ratio modifier isn't specific to image views, but it can be applied to any type of view. For example, here we're rendering a color with a fixed aspect ratio of 16×9. The color always fits or fills the available space using the provided aspect ratio.

Code
Color.pink    .aspectRatio(16/9, contentMode: .fit)
Preview
FitFill
150

In the initial image example, we didn't specify a fixed aspect ratio. By leaving the parameter off, the underlying view's ideal size is used to compute the aspect ratio. To compute the ideal size, the aspect ratio first proposes a nil×nil size to its child. The child's ideal size is used as the aspect ratio, and the aspect ratio then either fits or fills a rectangle with the computed ratio within its proposal.

Preview
Tree
FitFill
200

When we're loading an image, sometimes we know the size of the image but don't have the image cached. In this case, we can use aspectRatio to display a placeholder with the correct aspect ratio. If the placeholder itself is, for example, text, we can wrap it in a flexible frame to make sure it accepts the proposed size.

Code
Text("Hej!")    .frame(minWidth: 0,           maxWidth: .infinity,           minHeight: 0,           maxHeight: .infinity)    .background { Color.teal }    .aspectRatio(16/9, contentMode: .fit)
Preview
150

Gotchas

Perhaps surprisingly, the aspect ratio modifier only changes the proposal. For example, in the view below, it'll propose a square size to the text. However, as we can see from the border, the aspect ratio directly reports its child's size, and it doesn't report a square size.

Code
Text("Hello, world")    .aspectRatio(1, contentMode: .fit)    .border(Color.accentColor)
Preview