美文网首页Hacking with iOS: SwiftUI Edition
SwiftUI 布局: 了解 GeometryReader 内部

SwiftUI 布局: 了解 GeometryReader 内部

作者: 韦弦Zhy | 来源:发表于2020-12-15 19:55 被阅读0次

    \color{red}{\Large \mathbf{Hacking \quad with \quad iOS: SwiftUI \quad Edition}}

    {\Large \mathbf{GeometryReader}}

    SwiftUI的 GeometryReader 允许我们根据其自身的大小和坐标来确定视图的大小和坐标,这是在SwiftUI中创建一些出色的效果的关键。

    在使用GeometryReader时,您应始终牢记SwiftUI的三步布局系统:父级为子级提供了一个尺寸,子级使用该尺寸确定自己的尺寸,父级使用该尺寸适当地定位子级。

    在其最基本的用法中,GeometryReader的作用是让我们读取父级提供的大小,然后使用该大小来操纵我们的视图。例如,我们可以使用GeometryReader使文本视图具有所有可用空间的90%,而不管其内容是什么:

    struct ContentView: View {
        var body: some View {
            GeometryReader { geo in
                Text("Hello, World!")
                    .frame(width: geo.size.width * 0.9)
                    .background(Color.red)
            }
        }
    }
    

    传入的那个geo参数是一个GeometryProxy,它包含能够提供的最大的尺寸,已应用的所有安全区域,以及一种用于读取Frame 值的方法。

    GeometryReader有一个有趣的副作用,可能一开始会吸引您:返回的视图具有灵活的首选大小,这意味着它将根据需要扩展以占用更多空间。如果将GeometryReader放入VStack中,然后在其下放一些其他文本,则可以看到它的作用,如下所示:

    struct ContentView: View {
        var body: some View {
            VStack {
                GeometryReader { geo in
                    Text("Hello, World!")
                        .frame(width: geo.size.width * 0.9, height: 40)
                        .background(Color.red)
                }
    
                Text("More text")
                    .background(Color.blue)
            }
        }
    }
    

    您会看到“More text”被直接推到屏幕底部,因为GeometryReader占据了所有剩余空间。要查看实际效果,请将background(Color.green)作为修改器添加到GeometryReader中,您将看到它的大小。注意:这是首选大小,而不是绝对大小,这意味着它仍然可以灵活地取决于其父项。

    在读取视图Frame时,GeometryProxy提供了frame(in :)方法,而不是简单的属性。这是因为“Frame”的概念包括X坐标和Y坐标,这些坐标孤立地没有任何意义–您是要视图的绝对X坐标还是Y坐标,还是与父视图相比它们的X坐标和Y坐标?

    SwiftUI将这些选项称为坐标空间,特别是将这两个称为全局空间(相对于整个屏幕衡量我们的视图空间)和局部空间(相对于其父视图衡量我们的视图空间)。我们还可以通过将ordinateSpace()修饰符附加到视图来创建自定义坐标空间,然后该视图的任何子项都可以读取相对于该坐标空间的Frame。

    为了演示坐标空间是如何工作的,我们可以在不同的堆栈中创建一些示例视图,将自定义坐标空间附加到最外面的视图,然后在其中的一个视图中添加onTapGesture,以便它可以全局/局部地打印Frame和使用自定义坐标空间。

    尝试如下代码:

    struct OuterView: View {
        var body: some View {
            VStack {
                Text("Top")
                InnerView()
                    .background(Color.green)
                Text("Bottom")
            }
        }
    }
    
    struct InnerView: View {
        var body: some View {
            HStack {
                Text("Left")
                GeometryReader { geo in
                    Text("Center")
                        .background(Color.blue)
                        .onTapGesture {
                            print("Global center: \(geo.frame(in: .global).midX) x \(geo.frame(in: .global).midY)")
                            print("Custom center: \(geo.frame(in: .named("Custom")).midX) x \(geo.frame(in: .named("Custom")).midY)")
                            print("Local center: \(geo.frame(in: .local).midX) x \(geo.frame(in: .local).midY)")
                        }
                }
                .background(Color.orange)
                Text("Right")
            }
        }
    }
    
    struct ContentView: View {
        var body: some View {
            OuterView()
                .background(Color.red)
                .coordinateSpace(name: "Custom")
        }
    }
    

    该代码运行时所获得的输出取决于您所使用的设备,但这是我得到的:

    • Global center: 202.0 x 455.16666666666663
    • Custom center: 202.0 x 411.16666666666663
    • Local center: 164.0 x 378.5

    这些尺寸大部分是不同的,因此希望您能看到这些框架如何工作的全部内容:

    • 全局中心X为202表示文本视图的中心距离屏幕左边缘202个点。这并不是定死在屏幕中央,因为“Left”和“Right”标签的尺寸不同。
    • 全局中心Y为455.167表示文本视图的中心距离屏幕顶部边缘455.167点。这并不是定死在屏幕中央,因为顶部的安全区域比底部的安全区域大。
    • 自定义中心X为202表示文本视图的中心距拥有“自定义”坐标空间的任何视图的左边缘202个点,在本例中为OuterView,因为我们将其附加到ContentView中。此数字与全局位置匹配,因为OuterView水平边缘挨到屏幕边缘。
    • 自定义中心Y为411.167,表示文本视图的中心距离OuterView的顶部边缘为411.167点。该值小于全局中心Y,因为OuterView不会延伸到安全区域。
    • 局部中心X为164表示文本视图的中心距离其直接容器(在本例中为GeometryReader)的左边缘164个点。
    • Y的本地中心378.5表示文本视图的中心距离其直接容器(也是GeometryReader)的顶部边缘378.6点。

    您要使用哪个坐标空间取决于您要回答的问题:

    • 是否想知道此视图在屏幕上的位置?使用全局空间。
    • 是否想知道此视图相对于其父视图的位置?使用本地空间。
    • 要知道该视图相对于其他视图的位置?使用自定义空间

    Understanding frames and coordinates inside GeometryReader

    相关文章

      网友评论

        本文标题:SwiftUI 布局: 了解 GeometryReader 内部

        本文链接:https://www.haomeiwen.com/subject/wfowgktx.html