9
votes

How to set default spacing between rgb views (100pt) if their container (VStack) not conflicts with bottom black view.(like iPhone 11 Pro Max). BUT shrinks if there is no space for 100p height.(like iPhone SE on the screenshot)

My code:

struct ContentView: View {
    var body: some View {
        VStack(spacing: 0) {
            VStack(spacing: 0) {
                Rectangle()
                    .foregroundColor(.red)
                    .frame(height: 100)
                Spacer()
                    .frame(minHeight: 10, maxHeight: 100)
                Rectangle()
                    .foregroundColor(.green)
                    .frame(height: 100)
                Spacer()
                    .frame(minHeight: 10, maxHeight: 100)
                Rectangle()
                    .foregroundColor(.blue)
                    .frame(height: 100)
            }
            Spacer()
                .frame(minHeight: 10, maxHeight: 600)
            Rectangle() // keyboard
                .frame(height: 200)
        }
    }
}

So the problem is: Spacers with maxHeight: 100 have height = 10 (not 100) on iPhone 11 Pro Max. (BUT space between black view and VStack allows it)

How to make behavior I explained?

enter image description here

enter image description here

2

2 Answers

5
votes

You need to use idealHeight alongside with .fixedSize modifier for Spacers:

Spacer()
    .frame(minHeight: 10, idealHeight: 100, maxHeight: 600)
    .fixedSize()
0
votes

Use Spacer(minLength: 10) for the last spacer.

struct ContentView: View {
    var body: some View {
        VStack(spacing: 0) {
            VStack(spacing: 0) {
                Rectangle()
                    .foregroundColor(.red)
                    .frame(height: 100)
                Spacer()
                    .frame(minHeight: 10, maxHeight: 100)
                Rectangle()
                    .foregroundColor(.green)
                    .frame(height: 100)
                Spacer()
                    .frame(minHeight: 10, maxHeight: 100)
                Rectangle()
                    .foregroundColor(.blue)
                    .frame(height: 100)
            }
            Spacer(minLength: 10)
            Rectangle() // keyboard
                .frame(height: 200)
        }
    }
}

The problem in your code is that when you wrap a Spacer inside a frame like Spacer().frame(minHeight: 10, maxHeight: 600), it is first considered as a frame, then a Spacer inside that frame. And a frame has equal default layout priority as other views. So the parent will propose it the same amount of space as the inner VStack. By removing the frame modifier, the Spacer has the least layout priority, so the inner VStack will take as much space as possible except the minimum 10 points claimed by the spacer and 200 points for the rectangle.