2024-10-23 18:31:57
,某些文章具有时效性,若有错误或已失效,请在下方留言。几何读取器
使⽤⼏何读取器 (GeometryReader
),我们可以测量被建议的尺⼨。⼏何读取器⽆条件接受被建议尺⼨,并通过⼀个⼏何代理 (GeometryProxy) 将该尺⼨报告给它的视图构建器闭包。
通过⼏何代理,我们可以访问⼏何读取器的⼤⼩ (它的类型是 CGSize,表示读取器被建议的尺⼨,其中 nil
被默认值 10 点替代)。我们还可以读取安全区域的内移量 (inset
),在特定坐标空间中读取 frame
,以及解析锚点等。
当使⽤⼏何读取器测量视图的尺⼨时,我们建议将其放置在 overlay
或 background
中。overlay
的次要⼦视图所得到的建议尺⼨就是 overlay
的主要⼦视图的尺⼨。通过将⼏何读取器放置在 overlay
内,我们就可以测量主要⼦视图的尺⼨,同时不会影响布局。
首选项
在 SwiftUI 中,⾸选项是和环境所对应的概念。环境值负责将值沿着视图树向下传播,⽽ ⾸选项则将值沿着树向上传播。
PreferenceKey
协议需要⼀个默认值 。同时它还需要⼀个 reduce
⽅法,该⽅法⽤来组合两个值。例如,如果我们想测量多个视图的最⼤宽度,我们可以设定⼀个 CGFloat 值,并通过取最⼤值来实现 reduce
。
在我们的例⼦中,我们想要测量所有⼦视图的尺⼨。
struct SizeKey: PreferenceKey {
static var defaultValue: [CGSize] = []
static func reduce(value: inout [CGSize], nextValue: () -> [CGSize]) {
value.append(contentsOf: nextValue())
}
}
要测量单个视图,在 overlay
中使⽤⼏何读取器进⾏测量。在那⾥,我们使⽤⾸选项将此值传播到视图树的上层:
extension View {
func measureSize() -> some View {
overlay {
GeometryReader { proxy in
Color.clear
.preference(key: SizeKey.self, value: [proxy.size])
}
}
}
}
要测量多个视图的尺⼨,我们使⽤ ForEach ⽣成多个⼦视图,并在每个⼦视图上调⽤ measureSize
。此外,我们还在测量尺⼨的视图树上游的某个位置添加了 onPreferenceChange(_:perform:)
修饰符,并打印出⾸选项值:
ZStack(alignment: .topLeading) {
ForEach(0..<5) { ix in
Text("Item \(ix)" + String(repeating: "\n", count: ix / 2))
.padding()
.measureSize()
}
}
.onPreferenceChange(SizeKey.self) {
print($0)
}
当在 macOS 上运⾏时,print 语句将打印出⼀个包含所有尺⼨的数组:
[(80.33333333333333, 52.33333333333333), (77.33333333333333, 52.33333333333333)]
每个 .preference
修饰器的值都向上传递到视图树中,PreferenceKey
的 reduce
⽅法则被⽤来将来⾃多个⼦视图的值组合起来。⼀旦遇到带有相同键的 .onPreferenceChange(_ key:perform:)
修饰器,框架就会使⽤ .onPreferenceChange 内⼦树中的累加值来调⽤ perform
闭包。当影响⾸选项的状态更改发⽣时,此过程将从空⽩状态重新开始。
参考《Thinking In SwiftUI》
暂无评论内容