Touch layout not matching UI layout on iPhone after waking device when .sheet is open

In a SwiftUI app on iPhone when the device is put to sleep by pressing the power button, while the app is presenting a .sheet, waking the device will result in the touch layout to not match the UI layout. See attached project to reproduce the issue. This happens with Xcode 14.2, targeting iOS 16.0.

Steps to reproduce (assuming the app has been built an running on a real device, xcode project linked at the bottom):

  1. Tap the “Hello World” button. This opens a plain sheet with a fully green color content
  2. Push the device’s power button to put it to sleep
  3. Push the device’s power button again to wake the device
  4. Optionally unlock the device if needed
  5. Dismiss the opened green sheet (the app should still be open and displaying the sheet after waking the device)
  6. Try to tap the “Hello World” button again.

Observed behavior:

  • the area required to tap to activate the button no longer matches the UI and you have to tap below the button to activate it.

Desired behavior:

  • after waking the device and dismissing the sheet, the touch and ui layout should still be correct.

Demonstration XCode project

Just to confirm your observations -- interesting bug...

It also happens if you use App-Switcher to switch to another app -- no need to put the device to sleep. Also occurs using the Simulator.

Best way to see what's going on is - with your demonstration project:

  • launch the app
  • in Xcode, select View Debug Hierarchy
    • you'll see lots of rectangles (showing the various SwiftUI generated objects/layers), all aligned with the rendered button
  • continue execution
  • tap the button to present the green sheet
  • swipe up from the bottom or use App-Switcher to send this app to the background
  • switch back to this app and drag down to dismiss the green sheet
  • go back to Xcode and select View Debug Hierarchy again
    • you'll now see the misaligned rectangles

Note: if we then do something to force a layout update - such as rotate the device - the issue corrects itself.

You should file a bug report.

I’ve encountered this bug. I suspect it’s caused when the UIHostingController’s view is transformed from the presentation, messing up hit testing of controls.

I was able to find a workaround. The view’s frame needs to be “reset”, and then the SwiftUI views will fix themselves.

Upon dismissal, the UIHostingControllers view frame should be reset like this.

let frame = view.frame
view.frame = .zero
view.frame = frame

There are a few different ways you could achieve this, such as swizzling or getting the view controller from the current UIWindow.

I already created a issue in the feedback assistent at the same time as posting this on the dev forums -> FB11983439

@Apple Any feedback on this? Can we expect a fix on this or do I need to implement a workaround for this in our upcoming release? Btw, this is my current workaround. You can add this to any View you show within the sheet, popover, etc... and when it gets dismissed, it will 'reset' the layout.

  public func body(content: Content) -> some View {
    content
      .onDisappear {
        let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene
        if let viewFrame = scene?.windows.first?.rootViewController?.view.frame {
          scene?.windows.first?.rootViewController?.view.frame = .zero
          scene?.windows.first?.rootViewController?.view.frame = viewFrame
        }
      }
  }
}

public extension View {
  func syncLayoutOnDissappear() -> some View {
    modifier(SyncLayoutOnDissappear())
  }
}

Ok, made a copy-paste error. first line is missing: public struct SyncLayoutOnDissappear: ViewModifier {

This is still broken on iOS 16.4 and XCode 14.3

I found this in iOS 17's Beta release notes: Fixed: Gestures could be misaligned if an app was backgrounded while a sheet was presented. (99202394).

Hopefully this is referring to this particular issue.

Still broken on iOS 17.0 and Xcode 15-RC

I also opened a ticket: [https://developer.apple.com/forums/thread/738381] - [FB13206752]

I fixed this issue by using .presentationDetents([.fraction(yourFaction)]) while showing the sheet. Worked for me on iOS 16, XCode 15 (15A240d)

Touch layout not matching UI layout on iPhone after waking device when .sheet is open
 
 
Q