Search code examples
iosswiftuioverlaygeometryreader

SwiftUI erroneous vertical alignment of overlay when using GeometryReader


I have an overlay view that I want to appear hugging the top edge of its parent view (aligned vertically to top not center, see snapshot B) and have the ability to semi-hide it when tapped (move it up so that it doesn't obscure its parent view, and yet have a portion of it visible, say 64 pixels so that it can still be tapped back into original position, see snapshot C). Problem is that when I use the GeometryReader to get the height of the overlay view I'm trying to move, the overlay appears in the center of the view originally (see snapshot A). And if I don't use the geometry reader I don't know by how much to offset the overlay view:

    @State var moveOverlay = false

    var body : some View {

        VStack {
            ForEach(0...18, id: \.self) { _ in
                Text("This is the background... This is the background... This is the background... This is the background... ")
            }
        }
        .overlay(VStack {
            GeometryReader { proxy in
                Text("This is the overlay text snippet sentence that is multiline...\nThis is the overlay text snippet sentence that is multiline...\nThis is the overlay text snippet sentence that is multiline...\nThis is the overlay text snippet sentence that is multiline...\nThis is the overlay text snippet sentence that is multiline...\nThis is the overlay text snippet sentence that is multiline...\n")
                    .lineLimit(9)
                    .background(Color.gray)
                    .padding(32)
                    .frame(maxWidth: nil)
                    .offset(x: 0, y: self.moveOverlay ? -proxy.size.height + 128 + 64 : 0)
                    .onTapGesture {
                        self.moveOverlay = !self.moveOverlay
                }
            }
            Spacer()
        })
    }

Not sure why geometry reader has this effect on the layout.

(A) This is the way it appears with geometry reader code:

enter image description here

(B) If I remove the geometry reader code I get the desired effect:

enter image description here

(C) And this is the way I want the overlay when moved to the top:

enter image description here

EDIT: The code displayed above produces the layout (A). I want layout (B) which I get if I omit the geometry reader code.


Solution

  • Well... still not sure but here is some approach

    Tested with Xcode 11.4 / iOS 13.4

    demo

    .overlay(
        ZStack(alignment: .top) {
            Color.clear
            Text("This is the overlay text snippet sentence that is multiline...\nThis is the overlay text snippet sentence that is multiline...\nThis is the overlay text snippet sentence that is multiline...\nThis is the overlay text snippet sentence that is multiline...\nThis is the overlay text snippet sentence that is multiline...\nThis is the overlay text snippet sentence that is multiline...\n")
                    .lineLimit(9)
                    .background(Color.gray)
                    .alignmentGuide(.top) { self.hideOverlay ? $0.height * 3/2 : $0[.top] - 64 }
                    .onTapGesture {
                        withAnimation(Animation.spring()) {
                            self.hideOverlay.toggle()
                        }
                }
        })