One of many modifiers that all the time puzzled me a bit was .aspectRatio
. How does it actually work? As soon as I figured it out, it turned out to be less complicated than I believed.
One place the place we will discover out so much about how SwiftUI works is SwiftUI’s .swiftinterface
file. That is positioned inside Xcode. Inside your Terminal, go to /Functions/Xcode.app
, and carry out the next command:
discover . -path "*/SwiftUI.framework*swiftinterface"
There are a couple of variants of the .aspectRatio
API, however all of them boil right down to a single implementation:
func aspectRatio(_ aspectRatio: CGFloat?, contentMode: ContentMode) -> some View {
}
The variant with CGSize
simply calls this methodology with dimension.width/dimension.top
, and .scaledToFit
and .scaledToFill
name this methodology with the respective content material modes and an aspectRatio
of nil
.
After we name aspectRatio
with a hard and fast facet ratio, e.g. .aspectRatio(16/9, contentMode: .match)
, the facet ratio implementation takes the proposed dimension, and proposes a brand new dimension to its youngster. When the content material mode is .match
, it matches a rectangle with the specified facet ratio contained in the proposed dimension. For instance, if you suggest 100×100, it is going to suggest 100×56.2 to its youngster. While you select .fill
as a substitute, it is going to suggest 177.8×100 to its youngster as a substitute.
I found out this habits by printing the proposed sizes. Extra on that beneath.
Maybe the most typical use of aspectRatio
is mixed with a resizable picture, like so:
Picture("check")
.resizable()
.aspectRatio(contentMode: .match)
This can draw the picture to suit throughout the proposed dimension. Word that we don’t specify the precise facet ratio: it’s derived from the underlying picture.
After we do not specify a hard and fast facet ratio however use nil
for the parameter, the facet ratio modifier appears to be like on the splendid dimension of the underlying view. This implies it merely proposes nil×nil
to the underlying view, and makes use of the results of that to find out the facet ratio. For instance, when the picture stories its splendid dimension as 100×50, the computed facet ratio is 100/50
.
The method then continues like earlier than: when the view was proposed 320×480, the picture might be sized to 320×160 when the content material mode is about to .match
, and 960×480 when the content material mode is about to .fill
.
Determining proposed sizes
Proposed sizes are usually not a part of the general public API of SwiftUI. Though you completely want to grasp how this works with a purpose to write efficient layouts, this is not actually documented. The one official place the place this habits is described is within the wonderful 2019 WWDC speak Constructing Customized Views with SwiftUI.
Nevertheless, there’s a hack to do that. Contained in the interface file talked about above, I looked for “ProposedSize” and located a protocol named _ArchivableView
which permits us to override sizeThatFits
:
struct MySample: _ArchivableView {
var physique: some View {
Rectangle()
}
func sizeThatFits(in proposedSize: _ProposedSize) -> CGSize {
print(proposedSize.fairly)
return proposedSize.orDefault
}
}
We are able to now merely assemble a MySample
with a facet ratio and print the outcome. As a substitute of a .body
, you can even use .fixedSize()
to suggest nil for the width and/or top. Likewise, strive leaving out the primary parameter and see how .aspectRatio
proposes nil to determine the perfect dimension of its youngster view.
MySample()
.aspectRatio(100/50, contentMode: .fill)
.body(width: 320, top: 480)
Sadly the width
and top
properties on _ProposedSize
aren’t seen within the swift interface, so I had to make use of introspection to print these (and likewise add a couple of helper strategies like .fairly
and .orDefault
). The total code is in a gist.
If you wish to be taught extra about how SwiftUI works, learn our guide Considering in SwiftUI. When your organization is already constructing issues in SwiftUI — or is about to get began — contemplate reserving a SwiftUI Workshop on your group.