Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

swift

swiftui

I need to do calculations based on the size of the device and the width of a screen.

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)               
        }

    }
}
}

My ObservableObject can be seen below

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
     }
}

I need a way to pass the geometry.size.width to my ScreenSize property but have no idea how to do this.

like image 615
yawnobleix Avatar asked Oct 14 '25 04:10

yawnobleix


2 Answers

The simplest way is to have setter-method inside the ObservableObject which returns an 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()
    }
}

Then you could implement a wrapper around GeometryReader taking content: () -> Content and a closure which gets executed every time the GeometryReader gets rerendered where you can update whatever you wish.

import SwiftUI

struct TranslatorView: View {
    @ObservedObject var settings = TranslationViewModel(spacing: 4, charSize: 20)
    var body: some View {
        GeometryReaderEasy(callback: {
            self.settings.ScreenSize = $0.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)
            }
        }
    }
}
like image 186
Fabian Avatar answered Oct 17 '25 19:10

Fabian


You can use a simple extension on View to allow arbitrary code execution when building your views.

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

And then

var body: some View {
    GeometryReader { proxy
        Color.clear.execute {
            self.myObject.useProxy(proxy)
        }
    }
}
like image 35
arsenius Avatar answered Oct 17 '25 19:10

arsenius



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!