Skip to content

Instantly share code, notes, and snippets.

@jamesreggio
Last active August 3, 2016 17:59
Show Gist options
  • Save jamesreggio/d5233dba36b184ba3af3 to your computer and use it in GitHub Desktop.
Save jamesreggio/d5233dba36b184ba3af3 to your computer and use it in GitHub Desktop.
Bug report on UIScrollView or WKWebView, discovered while addressing Twitter IDYN-842

Keyboard inset adjustment double-counts toolbar height in WKWebView or UIScrollView

Since iOS 7, the navigation bar and toolbar[0] in a UINavigationController are designed to render atop the content of the current UIViewController. In order to prevent these bars from occluding the contents of the view, UINavigationController will (under certain conditions) automatically reach down the view hierarchy and adjust the insets of the primary UIScrollView, such that the content is padded by the height of these bars.

The system keyboard is also designed to occlude the bottom half of the screen by default. In most cases, this is undesirable, so the app developer is expected to subscribe to NSNotificationCenter keyboard events and adjust the UIScrollView insets themselves.

WKWebView automatically subscribes to these keyboard events and adjusts its UIScrollView insets to prevent keyboard occlusion. However, instead of taking the maximum of the keyboard and toolbar height (both of which are anchored at the bottom of the screen), it sums them together, creating extra bottom padding equivalent to the height of the toolbar.

[0] The navigation bar is the bar at the top (which typically contains the screen's title and a 'back' button), and the toolbar is the bar at the bottom (which typically contains action buttons).

WKWebView with keyboard hidden WKWebView with keyboard visible

Proposed solution

The logic to calculate these insets lives in a private helper method on UIScrollView, so its not clear whether this bug belongs to WKWebView, UIScrollView, or UINavigationController. I believe that this helper method (-[UIScrollView _adjustForAutomaticKeyboardInfo]) is the place where a MAX(keyboardHeight, contentInset.bottom) fix should be applied.

The disassembly from UIScrollView indicates the presence of certain keyboard-related inset properties, which may also possibly be leveraged to solve this problem, though due to the closed-source nature of UIKit, the solution is not immediately clear.

Detailed account of API calls

Initially, the main UINavigationController

  • inspects the inbound -[UIViewController automaticallyAdjustsScrollViewInsets] and returns early if it's set to NO
  • calculates the height of the navigation bar and toolbar
  • notifies the inbound UIViewController of the appropriate adjustments to contentInset and scrollIndicatorInset via this call chain, which it applies to its UIScrollView

If the current UIViewController contains a WKWebView, that WKWebView

  • subscribes to UIKeyboard notifications at this line, and upon notification
  • calls -[UIScrollView _adjustForAutomaticKeyboardInfo] at this line

Finally, -[UIScrollView _adjustForAutomaticKeyboardInfo]

  • obtains the height of the keyboard
  • adds it to its current bottom value for contentInset and scrollIndicatorInset
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment