Skip to content

Commit

Permalink
Fix broken keyboard layout after changing styles
Browse files Browse the repository at this point in the history
I'm assuming the motivation for the previous implementation is from
https://developer.apple.com/documentation/uikit/uiappearance :

> iOS applies appearance changes when a view enters a window, but it
> doesn’t change the appearance of a view that’s already in a window. To
> change the appearance of a view that’s currently in a window, remove the
> view from the view hierarchy and then put it back.

Note that we're removing views from not just our own application
windows, but all windows (including the keyboard window). By ignoring
the keyboard window, my layout issues go away.

Previous steps to reproduce:

1. add a map and an input field to the view hierarchy
2. make input field first responder to present keyboard (thus adds
   keyboard window to application)
3. present another MapView modally (triggers `applyStyle`, which in turn
   re-adds every view from every window.
4. dismiss the modal mapview
5. make input field first responder again

At this point, the views in my application all seem to be inexplicably
offset by the keyboard height.
  • Loading branch information
michaelkirk committed May 31, 2024
1 parent 3ffaa51 commit 98101b0
Showing 1 changed file with 13 additions and 1 deletion.
14 changes: 13 additions & 1 deletion MapboxNavigation/StyleManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ open class StyleManager: NSObject {
}

func forceRefreshAppearance() {
for window in UIApplication.shared.windows {
// re-adding the keyboard window views can break layout. See https://github.com/maplibre/maplibre-navigation-ios/issues/50
for window in UIApplication.shared.applicationWindows {
for view in window.subviews {
view.removeFromSuperview()
window.addSubview(view)
Expand Down Expand Up @@ -240,3 +241,14 @@ extension Solar {
}
}
}

extension UIApplication {
var applicationWindows: [UIWindow] {
windows.filter { window in
let className = String(describing: type(of: window))
return !className.contains("UIRemoteKeyboardWindow") &&
!className.contains("UITextEffectsWindow") &&
!className.contains("UIAlertController")
}
}
}

0 comments on commit 98101b0

Please sign in to comment.