GeometryReader acting weird when presenting a modal on iOS 16. Bug or new behavior?

Viewed 62

I'm seeing a weird behavior that is affecting one of my views in SwiftUI after upgrading to iOS 16.

Just to give some context, here is the stack:

  • Xcode 14
  • Simulator or real device on iOS 15.5 and 16

Considering the minimum reproducible code below:

struct ContentView: View {
    @State private var isPresented: Bool = false

    var body: some View {
        GeometryReader { reader in
            VStack(spacing: 36) {
                Text("Screen frame:\n\(String(describing: reader.frame(in: .global)))")
                    .multilineTextAlignment(.center)

                Button {
                    isPresented.toggle()
                } label: {
                    Text("Open modal")
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .padding()
            .onReceive(NotificationCenter.default.appDidBecomeActive()) { _ in
                print(reader.frame(in: .global))
            }
            .onReceive(NotificationCenter.default.appDidEnterBackground()) { _ in
                print(reader.frame(in: .global))
            }
        }
        .sheet(isPresented: $isPresented) {
            modalView
        }
    }

    private var modalView: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundColor(.accentColor)
            Text("Hello, world!")
        }
        .padding()
    }
}

extension NotificationCenter {
    func appDidBecomeActive() -> AnyPublisher<Notification, Never> {
        publisher(for: UIApplication.didBecomeActiveNotification).eraseToAnyPublisher()
    }

    func appDidEnterBackground() -> AnyPublisher<Notification, Never> {
        publisher(for: UIApplication.didEnterBackgroundNotification).eraseToAnyPublisher()
    }
}

As soon the view starts, it's possible to see the frame available due to the GeometryReader. Then following the steps:

  1. Open the modal view
  2. Send the app to the background
  3. Open the app again
  4. Close the modal

It's possible to see that the frame changed, and the values match with the 3D effect when a view is presenting another view, and it's never changing again to the right values unless you send the app again to the background or switch views (e.g. using a TabView).

I don't find anything on iOS release notes talking about it, so I supposed it must be a bug (I've filled out a bug report already).

On iOS 15, the frame value keeps stable at the same value.

I have a couple of views relying on the value of a GeometryReader, and it's causing my view to deform because of this issue. Does anyone know a way to force the recalculation for the GeometryReader for this case?

Any help is appreciated.

1 Answers

The issue won't occur if you control the display of the sheet with the new presentationDetents method, provided you do not request to cover the entire screen.

I modified your code as follows:

    .sheet(isPresented: $isPresented) {
        if #available(iOS 16, *) {
            modalView
                .presentationDetents([.fraction(0.99)])
        }
        else {
            modalView
        }
    }

The issue will remain if you request .fraction(1), i.e. covering the whole screen.

Related