Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

set @State var inside geometryReader

How is it possible to set a @State var inside a geometryReader?

This is my code:

@State var isTest:Int = 0

var body: some View {
    VStack{
        ForEach(self.test, id: \.id) { Test in
            VStack{
                GeometryReader { geometry in
                    self.isTest = 1

I try with a function but it doesn't work.

@State var isTest: Int = 0

func testValue() {
    self.isTest = 1
}

var body: some View {
    VStack{
        ForEach(self.test, id: \.id) { Test in
            VStack{
                GeometryReader { geometry in
                    testValue()

Any idea? Thanks!

like image 784
Stefano Vet Avatar asked Apr 15 '26 07:04

Stefano Vet


2 Answers

Xcode 16.0+:

You can use onGeometryChange(for:of:action:) with Xcode 16.0+ targeting iOS 16.0+ or macOS 13.0+:

struct MyView: View {
  @State private var size: CGSize = .zero

  var body: some View {
    ZStack {
      Text("Hello World")
    }
    .onGeometryChange(for: CGSize.self) { proxy in
      proxy.size
    } action: { newSize in
      size = newSize
    }
  }
}

Older Xcode:

You can use onAppear(perform:) to update @State variables with the initial view size and onChange(of:perform:) to update the variables when the view size changes:

struct MyView: View {
  @State private var size: CGSize = .zero

  var body: some View {
    GeometryReader { geometry in
      ZStack {
        Text("Hello World")
      }.onAppear {
        size = geometry.size
      }.onChange(of: geometry.size) { newSize in
        size = newSize
      }
    }
  }
}
like image 89
Madiyar Avatar answered Apr 22 '26 13:04

Madiyar


While putting code into function is a nice touch, there may arrive another problem and that is altering the @State variable during update phase: [SwiftUI] Modifying state during view update, this will cause undefined behavior

Using NotificationCenter to move @State variable update after view update phase can help, but one could use much more simple solution like performing variable update right after render phase by using DispatchQueue.

@State var windowSize = CGSize()

func useProxy(_ geometry: GeometryProxy) -> some View {

    DispatchQueue.main.async {
        self.windowSize = geometry.size
    }

    return EmptyView()
}

var body: some View {

    return GeometryReader { geometry in
        self.useProxy(geometry)    

        Text("Hello SwiftUI")        
    }
}
like image 32
vedrano Avatar answered Apr 22 '26 13:04

vedrano