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

Posted

技术标签:

【中文标题】SwiftUI 使用 GeometryReader 时覆盖层的错误垂直对齐【英文标题】:SwiftUI erroneous vertical alignment of overlay when using GeometryReader 【发布时间】:2020-04-26 17:44:04 【问题描述】:

我有一个覆盖视图,我希望它显示在其父视图的顶部边缘(垂直对齐到顶部而不是中心,请参见快照 B)并且能够在点击时半隐藏它(向上移动它以便它不会遮挡其父视图,但仍有一部分可见,例如 64 像素,因此仍可以将其轻敲回原始位置,请参见快照 C)。问题是当我使用GeometryReader 来获取我试图移动的覆盖视图的高度时,覆盖最初出现在视图的中心(参见快照A)。如果我不使用几何阅读器,我不知道要偏移多少覆盖视图:

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

不确定为什么几何阅读器会对布局产生这种影响。

(A) 这是几何阅读器代码的显示方式:

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

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

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

【问题讨论】:

我没有明白这一点。 我试图澄清。如果您仍然不清楚,请告诉我。 【参考方案1】:

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

使用 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 ? $0.height * 3/2 : $0[.top] - 64 
                .onTapGesture 
                    withAnimation(Animation.spring()) 
                        self.hideOverlay.toggle()
                    
            
    )

【讨论】:

您好!这有点离题,但它可能会改善我未来的答案:你如何制作那些漂亮的动画图像?我很想知道。 :-) @Asperi 这行得通,我喜欢alignmentGuide 覆盖(只要它完成工作,我就不必使用GeometryReader)。但是,当我使用 $0.height 时,它只会移动 $0.height/2 ——你有答案为什么吗?这是一个关于alignmentGuide 的一般问题,而不是您的具体答案。【参考方案2】:

您可以使用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)
            
    

【讨论】:

这是另一种选择,但是我不希望内容视图最初居中 - 我希望它紧贴屏幕的顶部边缘,然后向上移动,以便只有一部分是可见的(因此用户可以点击它以将其移回)。 一开始我没有意识到这一点,所以我相应地更新了答案。

以上是关于SwiftUI 使用 GeometryReader 时覆盖层的错误垂直对齐的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI - 计算 ScrollView 中长 GeometryReader 的高度

我们如何在 SwiftUI 中制作自定义 GeometryReader?

SwiftUI:如何在这种情况下将 .overlay 与 GeometryReader 一起使用?

SwiftUI - 如何使用 ObservedObject 或 EnvironmentObject 存储 GeometryReader 数据?

SwiftUI GeometryReader 体积小巧

SwiftUI - 如何从不同的视图中获取 GeometryReader 的大小/高度?