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):
Startview shows the picture and "Width 0 - Height 0" (WRONG)
Press the button to show the next view
View2 shows the picture and "Width 285 - Height 380" (WRONG)
Going back to the startview shows "Width 269 - Height 359" (CORRECT)
Switching to View2 still gives the wrong results (285, 380)
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]"