使用 GeometryReader 时 SwiftUI 覆盖层的垂直对齐错误

SwiftUI erroneous vertical alignment of overlay when using GeometryReader

我有一个覆盖视图,我希望它看起来紧贴其父视图的顶部边缘(垂直对齐到顶部而不是中心,请参见快照 B)并且能够在点击时半隐藏它(将其向上移动这样它就不会遮住它的父视图,但它的一部分是可见的,比如 64 像素,这样它仍然可以被点击回到原来的位置,见快照 C)。问题是,当我使用 GeometryReader 获取我试图移动的覆盖视图的高度时,覆盖最初出现在视图的中心(参见快照 A)。如果我不使用几何 reader 我不知道要偏移多少覆盖视图:

    @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()
        })
    }

不确定为什么几何 reader 对布局有这种影响。

(A) 这是它在几何体中的显示方式 reader 代码:

(B) 如果我删除几何 reader 代码,我会得到想要的效果:

(C) 这就是我想要的叠加层移动到顶部时的方式:

编辑:上面显示的代码生成布局 (A)。如果我省略几何 reader 代码,我想要布局 (B)。

好吧...仍然不确定,但这里有一些方法

测试 Xcode 11.4 / iOS 13.4

.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 ? [=10=].height * 3/2 : [=10=][.top] - 64 }
                .onTapGesture {
                    withAnimation(Animation.spring()) {
                        self.hideOverlay.toggle()
                    }
            }
    })

你可以使用func overlay<Overlay>(_ overlay: Overlay, alignment: Alignment = .center)中的第二个参数来实现它,通过将它对齐到顶端并根据模式向上或向下移动偏移量。

struct AlignmentView: View {
    @State var hideOverlay = false

    var body : some View {
        GeometryReader{ proxy in
            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(
                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)
                        .frame(maxWidth: nil)
                        .offset(x: 0, y: self.hideOverlay ? -proxy.size.height / 5.0 : 50)
                        .onTapGesture {
                            withAnimation {
                                self.hideOverlay.toggle()
                            }
            },
                alignment: .top)
            }
    }
}