maplibre / maplibre-navigation-ios

MapLibre Navigation SDK for iOS
Other
29 stars 27 forks source link

Fix broken keyboard layout after changing styles #51

Open michaelkirk opened 1 month ago

michaelkirk commented 1 month ago

FIXES #50

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.

Note there are a couple things I haven't tested yet:

I'll eventually add those things to my own app and be able to test them, but it might be some weeks. In the meanwhile, I thought it'd be good to have this PR available in case someone else hits this problem. It took me a while to track it down.

boldtrn commented 1 month ago

Thanks for looking into this. Yeah I think especially dark mode could potentially be an issue here. I agree that we should do some more testing on this. What I don't understand from your video, why is the keyboard suddenly open after the navigation? Because the keyboard was closed before starting the navigation. Is this intended? If yes, this feels quite exotic. (I am not saying, we shouldn't merge this, I'd just like to understand this a bit better)

michaelkirk commented 1 month ago

What I don't understand from your video, why is the keyboard suddenly open after the navigation

The keyboard is not suddenly open after navigation. It remains dismissed (12s-14s) until the user taps into the field (15s).

https://github.com/maplibre/maplibre-navigation-ios/assets/217057/4a75e8e3-475c-48d5-87ba-c876f17eacd7

I don't know the private implementation details of how iOS does keyboard presentation, but here's some debugging info that might be relevant:

Originally the app has just one UIWindow:

image

When the keyboard is first presented a UITextEffectsWindow is added:

image

After the input resigns first responder, the keyboard is dismissed, but the UITextEffectsWindow remains (though one of it's views is removed):

image

So that convinced me that even though the keyboard is not visible when the second MapView is dismissed, some of the keyboards containing views and windows have persisted. With the previous logic, those views were being removed and re-added to their window. It seems plausible for iOS to say "don't touch views in our private windows" unless you want things to break.

So my theory is that, by removing/re-adding the containing keyboard views to their window, we've broken something. But the breakage is not apparent until the keyboard is actually shown.