Same stale inset here, with a trigger that needs no accessibility settings: a rotation while a
plain TextField is focused. Filed as FB24706384 with a 37-line repro project (no third-party code).
Steps, starting in portrait:
- Root screen has .safeAreaInset(edge: .bottom) with a bar.
- Push a screen with a TextField and focus it (portrait keyboard, 335 pt).
- Rotate to landscape - the keyboard re-shows at the landscape height (208 pt).
- Go back while still in landscape.
- Rotate to portrait. Layout is correct at this point.
- Background the app, then foreground it.
Three things that line up with what you describe:
- UIWindow.safeAreaInsets.bottom and rootViewController.view.safeAreaInsets.bottom stay correct the
whole time (34 portrait, 20 landscape). Only SwiftUI's view-level inset is wrong.
- The keyboard was hidden with a well-formed notification at 14.68, and the value SwiftUI later
installs is that notification's height - in the orientation that is no longer current.
- The bad value is installed on didEnterBackground, not on foreground.
Two workarounds that measured clean here, since the thread has none:
- Remove .keyboard from UIHostingController.safeAreaRegions whenever no keyboard is presented and
restore it on keyboardWillShow. This keeps automatic keyboard avoidance working, and it also
fixed a second variant we hit through an SFSafariViewController keyboard.
Gate the removal on there being no first responder: when foregrounding back onto an editing
screen, keyboardWillShow arrives before sceneDidBecomeActive, so removing it unconditionally
breaks avoidance.
- .ignoresSafeArea(.keyboard, edges: .bottom) - but only applied outside .safeAreaInset. Applied
before the inset, on the inset's own content, or on the NavigationStack, the bug remains, which
makes the modifier look ineffective. That one cost us a while.
Does your case also survive a background/foreground cycle once the safe area is offset? If it does,
this looks like one defect with (at least) three entry points - yours, this one, and FB20386257,
where an out-of-process WebView keyboard leaves the same inset behind.