是否可以将 GeometryReader 的值传递给 @Observableobject

Is it possible to pass the values of GeometryReader to a @Observableobject

我需要根据设备的尺寸和屏幕的宽度进行计算。

struct TranslatorView: View {

@ObservedObject var settings = TranslationViewModel(spacing: 4, charSize: 20)
var body: some View {
    GeometryReader { geometry in
        VStack{
             TextField("Enter your name", text:self.$settings.translateString)               
        }

    }
}
}

下面可以看到我的ObservableObject

class TranslationViewModel: ObservableObject {
    @Published var translateString  = ""
    var ScreenSize : CGFloat = 0
    var spacing : CGFloat = 4
    var charSize : CGFloat = 20

    init(spacing: CGFloat, charSize : CGFloat) {
         self.spacing = spacing
        self.charSize = charSize
     }
}

我需要一种方法将 geometry.size.width 传递给我的 ScreenSize 属性 但不知道该怎么做。

最简单的方法是在 ObservableObject 中使用 setter 方法,其中 returns 和 EmptyView.

import SwiftUI

struct TranslatorView: View {
    @ObservedObject var settings = TranslationViewModel(spacing: 4, charSize: 20)
    var body: some View {
        GeometryReader { geometry in
            VStack{
                self.settings.passWidth(geometry: geometry)
                TextField("Enter your name", text:self.$settings.translateString)
            }

        }
    }
}

class TranslationViewModel: ObservableObject {
    @Published var translateString  = ""
    var ScreenSize : CGFloat = 0
    var spacing : CGFloat = 4
    var charSize : CGFloat = 20

    init(spacing: CGFloat, charSize : CGFloat) {
        self.spacing = spacing
        self.charSize = charSize
    }

    func passWidth(geometry: GeometryProxy) -> EmptyView {
        self.ScreenSize = geometry.size.width
        return EmptyView()
    }
}

然后你可以围绕 GeometryReader 实现一个包装器,采用 content: () -> Content 和一个每次 GeometryReader 重新渲染时都会执行的闭包,你可以在其中更新任何你想要的东西。

import SwiftUI

struct TranslatorView: View {
    @ObservedObject var settings = TranslationViewModel(spacing: 4, charSize: 20)
    var body: some View {
        GeometryReaderEasy(callback: {
            self.settings.ScreenSize = [=11=].size.width
        }) { geometry in
            TextField("Enter your name", text:self.$settings.translateString)
        }
    }
}

struct GeometryReaderEasy<Content: View>: View {
    var callback: (GeometryProxy) -> ()
    var content: (GeometryProxy) -> (Content)

    private func setGeometry(geometry: GeometryProxy) -> EmptyView {
        callback(geometry)
        return EmptyView()
    }

    var body: some View {
        GeometryReader { geometry in
            VStack{
                self.setGeometry(geometry: geometry)
                self.content(geometry)
            }
        }
    }
}

您可以在 View 上使用一个简单的扩展来允许在构建视图时执行任意代码。

extension View {
    func execute(_ closure: () -> Void) -> Self {
        closure()
        return self
    }
}

然后

var body: some View {
    GeometryReader { proxy
        Color.clear.execute {
            self.myObject.useProxy(proxy)
        }
    }
}

另一种选择是使用 .onAppear

设置值
struct TranslatorView: View {
    
    @ObservedObject var settings = TranslationViewModel(spacing: 4, charSize: 20)
    var body: some View {
        GeometryReader { geometry in
            VStack{
                TextField("Enter your name", text:self.$settings.translateString)
            } .onAppear {
                settings.ScreenSize = geometry.size.width
            }
        }
    }
}