什么是SwiftUI中的几何阅读器?

60

我正在学习SwiftUI,遇到了“GeometryReader”。我想知道什么时候以及为什么要使用它?

3个回答

113

更新

自从我发布了这个答案后,我还写了一篇关于 GeometryReader 如何工作的文章。请查看以下链接以获取更详细的解释: https://swiftui-lab.com/geometryreader-to-the-rescue/


GeometryReader 是一个视图,可以让您访问其父视图的大小和位置。例如:

struct MyView: View {
    var body: some View {
        GeometryReader { geometry in
           // Here goes your view content,
           // and you can use the geometry variable
           // which contains geometry.size of the parent
           // You also have function to get the bounds
           // of the parent: geometry.frame(in: .global)
        }
    }
}

我通常与 .background() 结合使用,以获取某些其他视图的边界。例如,文本视图很难预测它将来有多大。当我需要那些信息时,我使用这个技巧:

首先,我定义了一个名为 GeometryGetter 的视图:

struct GeometryGetter: View {
    @Binding var rect: CGRect
    
    var body: some View {
        return GeometryReader { geometry in
            self.makeView(geometry: geometry)
        }
    }
    
    func makeView(geometry: GeometryProxy) -> some View {
        DispatchQueue.main.async {
            self.rect = geometry.frame(in: .global)
        }

        return Rectangle().fill(Color.clear)
    }
}

然后,要获取TextView(或任何其他视图)的边界:

struct MyView: View {
    @State private var rect: CGRect = CGRect()

    var body: some View {
        Text("some text").background(GeometryGetter($rect))

        // You can then use rect in other places of your view:
        Rectangle().frame(width: 100, height: rect.height)
    }
}

针对某些用例,我在其他问题中发布了一些使用GeometryReader的答案。请查看以下内容:

移动文本字段以避免被键盘隐藏:https://dev59.com/FVMI5IYBdhLWcg3wUp42#56721268

如何使一个视图的大小与另一个视图相同在SwiftUI中:https://dev59.com/GFMI5IYBdhLWcg3wUp02#56661706

注意:

在GeometryGetter中,我添加了一个DispatchQueue.main.async {}来设置rect。否则,在某些情况下,可能会导致运行时警告: Modifying state during view update


2
更新了答案,包括一些使用案例。 - kontiki
1
自从我发表了这个答案,我添加了一个链接,链接到我写的有关GeometryReader的文章。这进一步扩展了答案。干杯! - kontiki
那个几何图形的方法非常有用。感谢您的发布。 - テッド
1
使用Geometry reader的方法非常有用,但我认为异步调用frame(in:)对于动态内容(例如列表中的视图)并不是一个好主意,这会导致崩溃。解决方法是同步获取框架,然后异步分派它。 - Aleyam
这种技术可能会因为你如何使用 rect 值而导致无限循环。在 WWDC 22 的 "使用 SwiftUI 组合自定义布局" 会议中讨论了这个问题,具体时间是在 18:20 标记处 https://developer.apple.com/videos/play/wwdc2022/10056/ - chunkyguy
显示剩余3条评论

3

在SwiftUI中,什么被称为Reader?

除了kontiki的回答之外,Reader是一种以函数形式定义其内容的容器视图。因此,它们可以访问和操作其parent。如果你更仔细地查看,它们是通用的结构体,现在在SwiftUI 2.0中有2个可用的reader:

请注意,这只是一种约定,它们不遵循任何特殊协议,更多的是遵循View协议。

GeometryReader

struct GeometryReader<Content: View> : View

这是一个容器视图,它根据自己的大小和坐标空间定义其内容的函数。因此,您可以检测到GeometryReader中任何视图的框架和位置更改以及当前状态。其中一个常见用途是在需要将不同的视图分别放置在具有相同(或相对)大小的单独堆栈中时。


ScrollViewReader

struct ScrollViewReader<Content: View> : View

这是一个视图,其子视图的定义是通过ScrollViewProxy函数来针对子视图中可滚动的视图进行的。因此,您可以访问一些滚动视图,例如在列表中滚动到特定项或类似功能。 为了减少重复,我没有提供示例,如果您想了解更多信息,请查看链接。

0

GeometryReader 是一种能够识别父视图几何形状的工具,这意味着当您在几何形状中创建一个视图时,您可以获得父视图的大小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接