SwiftUI - 在不修改 View 大小的情况下使用 GeometryReader

标签 swift swiftui

我有一个标题 View ,它使用 edgesIgnoringSafeArea 将其背景扩展到状态栏下方。要正确对齐标题​​ View 的内容/ subview ,我需要来自 GeometryReadersafeAreaInsets。但是,当使用 GeometryReader 时,我的 View 不再具有合适的尺寸。

不使用GeometryReader的代码

struct MyView : View {
    var body: some View {
        VStack(alignment: .leading) {
            CustomView()
        }
        .padding(.horizontal)
        .padding(.bottom, 64)
        .background(Color.blue)
    }
}

预览

Expected

代码使用 GeometryReader

struct MyView : View {
    var body: some View {
        GeometryReader { geometry in
            VStack(alignment: .leading) {
                CustomView()
            }
            .padding(.horizontal)
            .padding(.top, geometry.safeAreaInsets.top)
            .padding(.bottom, 64)
            .background(Color.blue)
            .fixedSize()
        }
    }
}

预览

enter image description here

有没有一种方法可以在不修改底层 View 大小的情况下使用 GeometryReader

最佳答案

标题中问题的答案:

  • 可以将 GeometryReader 包装在 .overlay().background() 中。这样做将减轻 GeometryReader 的布局更改效果。 View 将正常布局,GeometryReader 将扩展到 View 的完整大小,并将 geometry 发送到其内容构建器闭包中。
  • 也可以设置 GeometryReader 的 frame 来阻止它急于展开。

例如,此示例通过将 GeometryReader 包裹在覆盖层中来呈现蓝色矩形和位于矩形高度 3/4 处的“Hello world”文本(而不是矩形填满所有可用空间):

struct MyView : View {
    var body: some View {
        Rectangle()
            .fill(Color.blue)
            .frame(height: 150)
            .overlay(GeometryReader { geo in
                Text("Hello world").padding(.top, geo.size.height * 3 / 4)
            })
        Spacer()
    }
}

另一个通过在 GeometryReader 上设置框架来实现相同效果的示例:

struct MyView : View {
    var body: some View {
        GeometryReader { geo in
            Rectangle().fill(Color.blue)
            Text("Hello world").padding(.top, geo.size.height * 3 / 4)
        }
        .frame(height: 150)

        Spacer()
    }
}

Render with "Hello world" on 3/4th the height of a blue rectangle.

但是,有一些注意事项/不是很明显的行为

1

View modifiers 适用于它们应用之前的所有内容,而不适用于之后的任何内容。在 .edgesIgnoringSafeArea(.all) 之后添加的叠加层/背景将遵守安全区域(不参与忽略安全区域)。

此代码在安全区域内呈现“Hello world”,而蓝色矩形忽略安全区域:

struct MyView : View {
    var body: some View {
        Rectangle()
            .fill(Color.blue)
            .frame(height: 150)
            .edgesIgnoringSafeArea(.all)
            .overlay(VStack {
                        Text("Hello world")
                        Spacer()
            })

        Spacer()
    }
}

Render of "Hello world" inside the safe area.

2

.edgesIgnoringSafeArea(.all) 应用到背景使 GeometryReader 忽略 SafeArea:

struct MyView : View {
    var body: some View {
        Rectangle()
            .fill(Color.blue)
            .frame(height: 150)
            .overlay(GeometryReader { geo in
                VStack {
                        Text("Hello world")
                            // No effect, safe area is set to be ignored.
                            .padding(.top, geo.safeAreaInsets.top)
                        Spacer()
                }
            })
            .edgesIgnoringSafeArea(.all)

        Spacer()
    }
}

Render of "Hello world" ignoring the safe area.

可以通过添加多个叠加层/背景来组成多个布局。

3

测量的几何图形将可用于 GeometryReader 的内容。不以 parent 或 sibling 的观点;即使值被提取到 State 或 ObservableObject 中。如果发生这种情况,SwiftUI 将发出运行时警告:

struct MyView : View {
    @State private var safeAreaInsets = EdgeInsets()

    var body: some View {
        Text("Hello world")
            .edgesIgnoringSafeArea(.all)
            .background(GeometryReader(content: set(geometry:)))
            .padding(.top, safeAreaInsets.top)
        Spacer()
    }

    private func set(geometry: GeometryProxy) -> some View {
        self.safeAreaInsets = geometry.safeAreaInsets
        return Color.blue
    }
}

Runtime warning "Modifying state during view update, this will cause undefined behavior."

关于SwiftUI - 在不修改 View 大小的情况下使用 GeometryReader,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56859095/

相关文章:

ios - 想不通 NSLayoutConstraint 冲突

swift - 在这种情况下,如何使NavigationLink工作?我可以在其中添加按钮吗?

ios - 在 iOS 上将 SwiftUI View 转换为 PDF

ios - SwiftUI 中的双向无限 PageView

arrays - Swift,如何使用带索引的数组重新排序另一个数组

swift - 如何创建模态动画,其中向上滑动屏幕上半部分,向下滑动屏幕下半部分

swiftui - 在 SwiftUI 中将 SF Symbols 调整为相同大小看起来不正确

ios - SwiftUI:如何将核心数据对象传递给 View ?

xcode - iOS 版谷歌地图崩溃

ios - 以编程方式配置 SWRevealViewController?