I am encountering the following strange behaviour in SwiftUI. Assume these definitions:
import SwiftUI
let cardAspectRatio : CGSize? = CGSize(width: 63, height: 88)
extension View {
@ViewBuilder
func fitCardAspectRatio1() -> some View {
let ratio = cardAspectRatio!
self.aspectRatio(ratio, contentMode: .fit)
}
@ViewBuilder
func fitCardAspectRatio2() -> some View {
if let ratio = cardAspectRatio {
self.aspectRatio(ratio, contentMode: .fit)
} else {
fatalError()
}
}
func fitCardAspectRatio3() -> some View {
let ratio = cardAspectRatio!
return AnyView(self.aspectRatio(ratio, contentMode: .fit))
}
}
Should not all three methods behave equivalently? I know that internally they return different view types, but that shouldn't make a difference for the user, shouldn't it? In particular, consider the following situation:
struct YellowCard : View {
@ViewBuilder var body : some View {
Color.yellow.border(Color.blue).fitCardAspectRatio1()
}
}
YellowCard
uses fitCardAspectRatioX
. The YellowCard
is used in a YellowBoard
:
struct YellowBoard : View {
private func cardView(size: CGSize) -> some View {
return YellowCard().frame(width: size.width, height: size.height)
}
private func computeDimensions(_ size : CGSize) -> (card : CGSize, size : CGSize) {
let ratio = aspectRatio()
let factor = min(size.width / ratio.width, size.height / ratio.height)
let size = CGSize(width: factor * ratio.width, height: factor * ratio.height)
let cardWidth = size.width / 3
let cardHeight = size.height / 2
let card = CGSize(width: cardWidth, height: cardHeight)
return (card: card, size: size)
}
var body : some View {
GeometryReader { geom in
let dims = computeDimensions(geom.size)
VStack(spacing: 0) {
HStack(spacing: 0) {
ForEach(0 ..< 3) { _ in cardView(size: dims.card) }
}
HStack(spacing: 0) {
ForEach(3 ..< 5) { _ in cardView(size: dims.card) }
}
}
}.aspectRatio(aspectRatio(), contentMode: .fit)
}
func aspectRatio() -> CGSize {
let card = cardAspectRatio!
let width = 3 * card.width
let height = 2 * card.height
return CGSize(width: width, height: height)
}
}
This behaves as expected when YellowCard
is defined via fitCardAspectRatio1
. When for example running this on MacCatalyst and resizing the window with just a YellowBoard
in it, the board adapts to the sizes. But when using fitCardAspectRatio2
or fitCardAspectRatio3
instead in the definition of YellowCard
, the board will not adapt its size but just keep its initial size.
That surely is a bug? Or is this behaviour somehow to be expected?