Hacking with iOS: SwiftUI Edition

SwiftUI 布局: 了解 GeometryReader 内部

2020-12-15  本文已影响0人  韦弦Zhy

\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")
    }
}

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

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

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

Understanding frames and coordinates inside GeometryReader

上一篇下一篇

猜你喜欢

热点阅读