My app has an array hand
of a struct with a property let blatt: Image
. During init
, an Image
is assigned to this property.
To display such an array horizontally, I use the following code (scaledWidth
is some constant):
HStack(spacing: 10) {
ForEach((0 ..< hand.count), id: \.self) {
hand[$0].blatt
.resizable()
.scaledToFit()
.frame(height: scaledWidth)
.border(.black)
}
}
This gives the following output:
This is what I expected.
Another array is to be displayed vertically. For this, I am using the following code:
VStack(spacing: 10) {
ForEach((0 ..< hand.count), id: \.self) {
hand[$0].blatt
.resizable()
.scaledToFit()
.rotationEffect(Angle(degrees: 90))
.frame(width: scaledWidth, height: scaledWidth)
.border(.black)
}
}
This gives additionally the following output:
Here, the height of each frame, as indicated by the bordered frame, is the height of the unrotated image.
Since I know the aspect ratio aspectRatioBlatt
of the images, I can adjust the output using .frame(width: scaledWidth, height: scaledWidth / aspectRatioBlatt)
. Then, the frames have the correct dimensions and the correct spacing, but the images inside are too little. Again, the height of the frame is then equal to the height of the inner unrotated image.
I have tried many view modifiers and multiple combinations, but failed. I even tried to use a custom layout as suggested here for vertical Text, but this did not work either.
Of course I could use a 2nd set of turned images, but it should be possible without it in SwiftUI.
How to do it right?
It might be simplest to rotate the HStack
instead.
Otherwise, if you know the aspect ratio then you can set the frame size before rotation and then adjust the height after rotation:
struct ContentView: View {
let width = CGFloat(50)
let aspectRatio = 31.0 / 15.0
let colors: [Color] = [.green, .blue, .mint, .teal, .purple]
var body: some View {
VStack(spacing: 50) {
HStack(spacing: 10) {
ForEach((0 ..< colors.count), id: \.self) { index in
Image(systemName: "figure.wave")
.resizable()
.scaledToFit()
.frame(width: width, height: width * aspectRatio)
.background { colors[index] }
.border(.black)
}
}
VStack(spacing: 10) {
ForEach((0 ..< colors.count), id: \.self) { index in
Image(systemName: "figure.wave")
.resizable()
.scaledToFit()
.frame(width: width, height: width * aspectRatio)
.background { colors[index] }
.border(.black)
.rotationEffect(.degrees(90))
.frame(height: width)
}
}
}
}
}
I found it also worked by setting only the width and then using scaledToFill
:
struct ContentView: View {
let width = CGFloat(50)
let colors: [Color] = [.green, .blue, .mint, .teal, .purple]
var body: some View {
VStack(spacing: 50) {
HStack(spacing: 10) {
ForEach((0 ..< colors.count), id: \.self) { index in
Image(systemName: "figure.wave")
.resizable()
.scaledToFit()
.frame(width: width)
.background { colors[index] }
.border(.black)
}
}
VStack(spacing: 10) {
ForEach((0 ..< colors.count), id: \.self) { index in
Image(systemName: "figure.wave")
.resizable()
.scaledToFill()
.frame(width: width)
.background { colors[index] }
.border(.black)
.rotationEffect(.degrees(90))
.frame(height: width)
}
}
}
}
}