2

I am trying to optimize a UI with VStacks and spacers in between. The UI is ideally designed for the iPhone 13 Pro screen size (left). For smaller devices, the intention is that the spacers will shrink in a certain way that the UI still looks appealing.

UI Mock

I tried to achieve this by using frames for the Spacers with minHeight, idealHeight and maxHeight. The intended layout appears on the iPhone 13 Pro, but on a smaller device like the iPhone SE the spacers don't scale down to the minWidth. How can I fix that?

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(spacing: 0) {
            // Top Space
            Spacer()
                .frame(minHeight: 16, idealHeight: 32, maxHeight: .infinity)
                .fixedSize()
            
            // VStack 1
            VStack(spacing: 0) {
                // Image placeholder
                Rectangle()
                    .fill(Color.red)
                    .frame(height: 175)
                
                Spacer()
                    .frame(minHeight: 15, idealHeight: 62, maxHeight: .infinity)
                    .fixedSize()
                
                Text("Abc")
                    .frame(height: 100)
            }
            .background(Color.gray)
            
            // Middle Space
            Spacer()
                .frame(minHeight: 22, idealHeight: 100, maxHeight: .infinity)
                .fixedSize()
            
            // VStack 2
            VStack(spacing: 0) {
                // Image placeholder
                Rectangle()
                    .fill(Color.red)
                    .frame(height: 100)
                
                Spacer()
                    .frame(minHeight: 15, idealHeight: 35, maxHeight: .infinity)
                    .fixedSize()
                
                // Image placeholder
                Rectangle()
                    .fill(Color.red)
                    .frame(height: 195)
            }
            .background(Color.gray)
            
            // Bottom Space
            Spacer()
                .frame(minHeight: 16, idealHeight: 45, maxHeight: .infinity)
                .fixedSize()
        }
        .edgesIgnoringSafeArea(.all)
    }
}
FrankZp
  • 2,022
  • 3
  • 28
  • 41
  • Try checking the size of the screen with `GeometryReader` or `UIScreen.main.bounds`. But note that `GeometryReader` takes up all available space and `UIScreen.main.bounds` won't automatically update after an orientation change. – aheze Jan 23 '22 at 19:11
  • @aheze How would knowing the screen size help with resizing the spacers? I would like to define a minimum value for a spacer and an ideal value. If the ideal value is not possible, the spacer should shrink with smaller device sizes until the minimal value is reached – FrankZp Jan 23 '22 at 19:13
  • 1
    But how will SwiftUI know whether to use the ideal value or the minimum value? Currently it's always using the ideal value since you set `fixedSize` — it's can't know automatically. Instead you can set the height with something like `UIScreen.main.bounds.width < 400 ? 15 : 35`. – aheze Jan 23 '22 at 19:17

1 Answers1

2

I'd suggest to wrap everything in another VStack and use it's spacing. You can read out the UIScreen bounds in the init of the view and compare it to the bounds of all devices.

struct SpacerTest: View {


var spacing: CGFloat

init() {
    let screenHeight = UIScreen.main.bounds.size.height
    
    if screenHeight < 500 {
        self.spacing = 20
    } else if screenHeight < 600 {
        self.spacing = 50
    } else {
        self.spacing = 100
    }
}

var body: some View {
    VStack(spacing: spacing) {
        Text("Spacing Test")
        Text("Spacing Test")
    }
}

}

wildcard
  • 896
  • 6
  • 16