swiftswiftui

Popover content misaligned inside safe area


I have a .popover with some content. I want it to ignore the safe area and function just as it would normally. This is what it should look like:

enter image description here

However, the content has a gap for the safe are and overflows on the other side.

HStack {
    Text("")
        .popover(isPresented: .constant(true)) {
            RoundedRectangle(cornerRadius: 20).fill(.green)
                .frame(width: 150)
                .padding(10)
                .presentationCompactAdaptation(.popover)
        }
    Spacer()
}
.ignoresSafeArea(.all)

(I'm using an iPhone with safe area in landscape here)

enter image description here

If I add .ignoresSafeArea(.all) to the RoundedRectange it ignores the "arrow inset", which looks just as broken:

RoundedRectangle(cornerRadius: 20).fill(.green)
  //...
  .ignoresSafeArea(.all) // <- also doesn't fix it

enter image description here

Is there a way to fix this?


Solution

  • Through some experiments, it seems like the rectangle seems to be shifted to the right, by half of the safe area width.

    You can read the safe area using a GeometryReader, and give a negative x offset:

    GeometryReader { geo in
    
        // GeometryReader changes how the views are laid out - this VStack is to vertically centre the HStack
        VStack {
            Spacer()
            HStack {
                Text("")
                    .popover(isPresented: .constant(true), arrowEdge: .top) {
                        RoundedRectangle(cornerRadius: 20).fill(.green)
                            .frame(width: 150)
                            .padding(100)
                            .presentationCompactAdaptation(.popover)
                            .offset(x: -geo.safeAreaInsets.leading / 2)
                    }
                
                Spacer()
            }
            Spacer()
        }
    
        // this should be on the view that is inside of the GeometryReader, not on the GeometryReader itself
        .ignoresSafeArea(.all)
    }