SwiftUI GeometryReader 与坐标系

GeometryReader 是一个通过闭包来构建视图的容器,可以返回一个 GeometryProxy 类型的结构体,它包含如下属性和方法,由此我们可以获取当前视图容器(即父视图)的尺寸和位置,绘制以其为参考坐标系的视图。

1
2
3
4
5
6
7
8
var safeAreaInsets: EdgeInsets
// The safe area inset of the container view.

var size: CGSize
// The size of the container view.

func frame(in: CoordinateSpace) -> CGRect
// Returns the container view’s bounds rectangle, converted to a defined coordinate space.

比如,我们需要绘制一个长宽均为父视图一半的矩形:

1
2
3
4
5
6
7
8
9
10
struct ContentView: View {
var body: some View {
GeometryReader { gr in
RoundedRectangle(cornerRadius: 10)
.fill(Color.blue)
.frame(width: gr.size.width * 0.5, height: gr.size.height * 0.5)
.position(x: gr.frame(in: .local).midX, y: gr.frame(in: .local).midY)
}
}
}

我们再来看看 GeometryProxy 包含的实例方法:func frame(in: CoordinateSpace) -> CGRect,这里的 CoordinateSpace 是个枚举类型,有以下几种情况:

1
2
3
case global // 参考系为屏幕
case local // 参考系为父视图
case named(AnyHashable) // 参考系为自定义

通过这个方法,我们可以获取到当前视图在不同参考系中的位置和尺寸,我们将代码改成如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
struct ContentView: View {
var body: some View {
VStack(spacing: 10) {
text("Top", width: 100, height: 50)

HStack(spacing: 10) {
text("Left", width: 50, height: 100)
roundRect
.background(Color.black)
text("Right", width: 50, height: 100)
}

text("Bottom", width: 100, height: 50)
}
.coordinateSpace(name: "VStack")
}

var roundRect: some View {
GeometryReader { gr in
RoundedRectangle(cornerRadius: 10)
.fill(Color.blue)
.frame(width: gr.size.width * 0.5, height: gr.size.height * 0.5)
.position(x: gr.frame(in: .local).midX, y: gr.frame(in: .local).midY)
.onTapGesture {
print("screen: \(UIScreen.main.bounds)")
print("global: \(gr.frame(in: .global))")
print("local: \(gr.frame(in: .local))")
print("custom: \(gr.frame(in: .named("VStack")))")
}
}
}

func text(_ text: String, width: CGFloat, height: CGFloat) -> some View {
Text(text)
.frame(width: width, height: height)
.background(Color.orange)
.cornerRadius(10)
}
}

运行模拟器 iPhone 12 Pro(safeAreaInsets: 47.0, 0.0, 34.0, 0.0),点击蓝色区域,控制台打印如下结果:

1
2
3
4
screen: (0.0, 0.0, 390.0, 844.0)
global: (60.0, 107.0, 270.0, 643.0)
local: (0.0, 0.0, 270.0, 643.0)
custom: (60.0, 60.0, 270.0, 643.0)

这与我们之前所说的枚举类型对应的坐标参考系是一致的。

您的支持将鼓励我继续创作!
0%