我想建立一个独立于ContentView的函数,我可以使用这个函数来初始化一些值,例如在这个向下的代码中,我想获得视图的大小与函数,但未知的原因对我来说它返回零,我认为后台修改不工作,因为我想在这个构建。任何帮助吗?
func viewSizeReaderFunction<Content: View>(content: Content) -> CGSize {
var sizeOfView: CGSize = CGSize()
content
.background(
GeometryReader { geometry in
Color
.clear
.onAppear() { sizeOfView = geometry.size }
})
return sizeOfView
}
let sizeOfText: CGSize = viewSizeReaderFunction(content: Text("Hello, world!"))
struct ContentView: View {
var body: some View {
Color.red
.onAppear() {
print(sizeOfText)
}
}
}
一般的想法是让视图使用preference
报告它的大小,并创建一个视图修饰符来捕获它。但是,就像@RobNapier说的,结构必须在视图层次结构中,因此在渲染上下文中,能够讨论大小。
struct SizeReporter: ViewModifier {
@Binding var size: CGSize
func body(content: Content) -> some View {
content
.background(GeometryReader { geo in
Color.clear
.preference(key: SizePreferenceKey.self, value: geo.size)
})
.onPreferenceChange(SizePreferenceKey.self, perform: { value in
size = value
})
}
}
我们需要定义SizePreferenceKey
:
extension SizeReporter {
private struct SizePreferenceKey: PreferenceKey {
static let defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
}
你可以在View
上创建一个方便的方法:
extension View {
func getSize(_ size: Binding<CGSize>) -> some View {
self.modifier(SizeReporter(size: size))
}
}
,像这样使用:
@State var size: CGSize = .zero
var body: some View {
Text("hello").getSize($size)
}
视图只是描述视图布局的数据。它们不是代表实际"视图"的对象。就像UIView那样。它们没有自己的逻辑或状态(这就是为什么它们需要@State
变量而不仅仅是var
)。
你写的代码给sizeOfView
分配了一个零大小,然后创建了一个视图结构,立即被扔掉,然后返回sizeOfView
。没有任何东西对View结构求值。我希望编译器会给你一个警告,比如&;result of call to background is unused.&;
你描述的方式是使用Preferences,.onPreferenceChange
,通常是@State
。关于Stack Overflow有很多答案。
https://stackoverflow.com/search?q=%5Bswiftui%5D +大小+ +视图的
这里有一个例子,特别注意.hidden()
:
的使用extension View {
func saveSize(handler: @escaping (CGSize) -> Void) -> some View {
return self
.background(
GeometryReader { geometry in
Color.clear
.onAppear {
handler(geometry.size)
}
})
}
}
struct ContentView: View {
@State var sizeOfText: CGSize = .zero
var body: some View {
ZStack {
Color.red
.onAppear() {
print(sizeOfText)
}
Text("Hello, world!")
.hidden()
.saveSize { sizeOfText = $0 }
}
}
}
请注意,这段代码有点危险,因为它依赖于onAppear
被调用的顺序,而这是不保证的。在实践中,通常需要处理尚未设置大小的情况。这可以通过Preferences变得更健壮,但这往往会带来很多麻烦。