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?