如何使一个函数采取视图,并在SwiftUI返回自定义结果?



我想建立一个独立于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变得更健壮,但这往往会带来很多麻烦。

相关内容

最新更新