SwiftUI. How to set shrink behavior for Spacer?
Asked Answered
A

4

16

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

Ammadis answered 2/12, 2019 at 9:15 Comment(0)
L
15

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

Spacer()
    .frame(minHeight: 10, idealHeight: 100, maxHeight: 600)
    .fixedSize()
Literature answered 2/12, 2019 at 9:25 Comment(0)
C
5

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.

Cutout answered 14/12, 2020 at 2:42 Comment(0)
M
0

I ran into a similar problem...

This fixed it for me:

Spacer().frame(minWidth: 0)
Metalepsis answered 7/12, 2022 at 20:23 Comment(0)
A
0

Simply doing

Spacer(minLength: 0)

fixed this issue for me!

NOTE: Using

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

Will NOT work correctly when you want your spacer to expand and also contract.

Aluin answered 23/5 at 3:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.