GeometryReader in NavigationStack gives wrong results

Hello, I came across a strange behaviour of GeometryReader in a NavigationStack. I want to get the size of an image view on the screen, so I add a .background modifier with a GeometryReader inside

.background( GeometryReader { geo in
                        Color.clear
                            .onAppear {
                                imgW = geo.size.width
                                imgH = geo.size.height
                            }

When I use this on a pure image view it works fine.

When this image is inside a NavigationStack I get wrong results when the image is shown the first time. But I get the right results when I move to the next view and come back to this view. Now GeometryReader gives the right size.

Is it a bug or do I miss something?

For demonstration I wrote a short program with 3 views:

import SwiftUI

class Router: ObservableObject {
    @Published var path = NavigationPath()
}

enum Routes: String, CaseIterable, Hashable {
    case View2, View3
}

struct ContentView: View {
    @StateObject var router = Router()
    @State private var imgSize = CGSize()
    
    var body: some View {
       
        NavigationStack(path: $router.path) {
            VStack {
                Image(uiImage: UIImage(named: "testpicture")!)
                    .resizable()
                    .scaledToFit()
                    .background( GeometryReader { geo in
                        Color.clear
                            .onAppear {
                                imgSize = geo.size
                            }
                    })
                Text("Width \(Int(imgSize.width)) - Height \(Int(imgSize.height))")
                
                Button {
                    router.path.append(Routes.View2)
                } label: {
                    Text("Press for next view")
                }
            }
            .navigationDestination(for: Routes.self) { route in
                switch route {
                case .View2:
                    View2()
                case .View3:
                    View3()
                }
            }
        }
        .environmentObject(router)
    }
}


struct View2: View {
    @EnvironmentObject var routes: Router
    @State private var imgSize = CGSize()
    
    var body: some View {
        VStack {
            Image(uiImage: UIImage(named: "testpicture")!)
                .resizable()
                .scaledToFit()
                .background( GeometryReader { geo in
                    Color.clear
                        .onAppear {
                            imgSize = geo.size
                        }
                })
            Text("Width \(Int(imgSize.width)) - Height \(Int(imgSize.height))")
            Button {
                routes.path.append(Routes.View3)
            } label: {
                Text("Press for next view")
            }
        }
        .navigationTitle("View 2")
        .navigationBarTitleDisplayMode(.inline)
    }
}

struct View3: View {
    @EnvironmentObject var routes: Router
    
    var body: some View {
        VStack {
            Text("Hello World")
            Text("& Friends")
        }
        .navigationTitle("View 3")
    }
}

"testpicture" is a normal photo in the assets section.

Test in landscape mode (iPhone 15 plus simulator):

  1. Startview shows the picture and "Width 0 - Height 0" (WRONG)
  2. Press the button to show the next view
  3. View2 shows the picture and "Width 285 - Height 380" (WRONG)
  4. Going back to the startview shows "Width 269 - Height 359" (CORRECT)
  5. Switching to View2 still gives the wrong results (285, 380)
  6. Going to View3 and back to View2 gives the CORRECT result ("Width 236 - Height 315")

Same behaviour on a real device.

Side note: Going to View3 and back again to View2 gives on every transfer a warning: "Failed to create 0x132 image slot (alpha=1 wide=1) (client=0xe03620e7) [0x5 (os/kern) failure]"

Answered by FrankDev123 in 807642022

As usual: after I searched for a topic without success, I post in a forum, search again .... and find the solution. On stackoverflow there is a post describing this problem and the answer for NavigationView https://stackoverflow.com/questions/67327453/geometryreader-with-navigationview-in-swiftui-is-initially-giving-zero-for-size).

The solution is to use ".onChange(of: geo.size)".

Accepted Answer

As usual: after I searched for a topic without success, I post in a forum, search again .... and find the solution. On stackoverflow there is a post describing this problem and the answer for NavigationView https://stackoverflow.com/questions/67327453/geometryreader-with-navigationview-in-swiftui-is-initially-giving-zero-for-size).

The solution is to use ".onChange(of: geo.size)".

GeometryReader in NavigationStack gives wrong results
 
 
Q