1
struct CircleTestView: View {
    let diameter: CGFloat = 433

    var body: some View {
        ZStack {
            Color(.yellow)
                .ignoresSafeArea()
        
            VStack {
                Circle()
                    .fill(Color(.green))
                    .frame(width: diameter, height: diameter)
                    .padding(.top, -(diameter / 2))
                Spacer()
            }
        
            VStack {
                Spacer()
                Button {} label: {
                    Color(.red)
                        .frame(height: 55)
                        .padding([.leading, .trailing], 16)
                }
            }
        }
    }
}

The code above creates the first image, yet for some reason if I remove the line the sets the frame for the Circle (ie. .frame(width: diameter, height: diameter)) I get the second image.

  1. enter image description here 2. enter image description here

I want the circle how it is in the first screen, and the button how it is in the second screen, but can't seem to achieve this. Somehow setting the frame of the Circle is affecting the other views, even though they're in a ZStack. Is this a bug with ZStacks, or am I misunderstanding how they work?

Grambo
  • 887
  • 8
  • 25
  • Use a geometry reader to make the width of the button a percentage of the view – lorem ipsum Dec 06 '21 at 16:38
  • ZStack fits the biggest subview. Circle itself does not have size, so when you remove explicit frame it just fits the screen. Your button does not have width as well, because Color does not have (similarly to Circle), so it just adjusted to what space is availalble. Now you should see how it goes so try again. – Asperi Dec 06 '21 at 16:48
  • @Grambo, any conclusions on the subject? – vigdora Aug 22 '22 at 11:17

1 Answers1

0

Lets call this one approach a:

struct CircleTestView: View {
let diameter: CGFloat = 433

var body: some View {
    ZStack {
        Color(.yellow)
            .ignoresSafeArea()
    
        VStack {
            Circle()
                .fill(Color(.green))
                .frame(width: diameter, height: diameter)
                .padding(.top, -(diameter / 2))
            Spacer()
        }
    
        VStack {
            Spacer()
            Button {} label: {
                Color(.red)
                    .frame(height: 55)
            }
        }
        .padding(.horizontal, 16)
        }
    }
}

Lets call this one approach b:

struct CircleTestView: View {
let diameter: CGFloat = 433

var body: some View {
    ZStack {
        Color(.yellow)
            .ignoresSafeArea()
    
        VStack {
            Circle()
                .fill(Color(.green))
                .offset(x: 0, y: -(diameter / 1.00))
            // increment/decrement the offset by .01 example:
            // .offset(x: 0, y: -(diameter / 1.06))
            Spacer()
        }
    
        VStack {
            Spacer()
            Button {} label: {
                Color(.red)
                    .frame(height: 55)
                    .padding([.leading, .trailing], 16)
            }
         }
      }
   }
}

A combination of the two approaches would land you at approach c. Do any of these achieve what you are looking for?

Tim Sonner
  • 146
  • 1
  • 6