所以我使用
GeometryReader
来读取容器的可用宽度。然后我计算按钮应该有多大,这决定了真实的大小。然而,GeometryReader 似乎不知道其子级的大小。
您应该如何告诉 GeometryReader 它的真实大小?
我的猜测是:
import SwiftUI
struct ContentView: View {
@State private var containerHeight: Double = 0.0
var body: some View {
GeometryReader { proxy in
Text("Test")
.task { containerHeight = calculateCustomHeight(using: proxy) }
}
.frame(height: containerHeight)
}
}
这有效。但是我不太确定这是 SwiftUI 方式还是无限循环。
计算容器高度,更新
@State
,更新视图,计算容器高度,更新@State
等
我认为它现在可以工作,因为值是相同的,因此不会触发视图的另一次更新。
我假设您想获取视图的大小值并稍后使用它。这可以通过使用首选项来完成。
PreferenceKey
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
PreferenceKey
实现
PreferenceKey
并在所需视图上使用 GeometryReader
来提取其大小。
.background {
GeometryReader { geometry in
Color.clear.preference(key: SizePreferenceKey.self,
value: geometry.size)
}
}
.onPreferenceChange(SizePreferenceKey.self) { size in
print("size of the red text is: \(size)")
// use the value however you want
sizeOfText = size
}
整个代码如下所示:
struct GeometryReaderTest: View {
@State private var sizeOfRedText: CGSize = .zero
var body: some View {
VStack {
Text("Green text")
.background { Color.green }
Text("Red text")
.background { Color.red }
// PreferenceKey & GeometryReader usage
.background {
GeometryReader { geometry in
Color.clear.preference(key: SizePreferenceKey.self,
value: geometry.size)
}
}
}
.onPreferenceChange(SizePreferenceKey.self) { size in
print("size of the red text is: \(size)")
// use the value however you want
sizeOfRedText = size
}
}
}
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
您可以创建一个
extension
来方便地提取项目中不同视图的大小。
extension View {
func getSizeOfView(_ getSize: @escaping ((CGSize) -> Void)) -> some View {
return self
.background {
GeometryReader { geometry in
Color.clear.preference(key: SizePreferenceKey.self,
value: geometry.size)
.onPreferenceChange(SizePreferenceKey.self) { value in
getSize(value)
}
}
}
}
}
然后你可以像这样调用
getSizeOfView
:
Text("Red text")
.background { Color.red }
.getSizeOfView { size in
print("size of the red text is: \(size)")
sizeOfRedText = size
}