michaeltyson / TPKeyboardAvoiding

A drop-in universal solution for moving text fields out of the way of the keyboard in iOS
http://atastypixel.com/blog/a-drop-in-universal-solution-for-moving-text-fields-out-of-the-way-of-the-keyboard/
zlib License
5.81k stars 925 forks source link

Prevent bottom content inset from being negative. #276

Closed wooster closed 3 years ago

wooster commented 5 years ago

On an iPad with a hardware keyboard and the shortcuts bar enabled:

If the scroll view has a bounds of:

CGRectMake(0, 138, 787, 327)

and the keyboard has a bounds of:

CGRectMake(0, 713, 1024, 55)

Then the bottom inset ended up being -107, which would make the bottom content of the scroll view inaccessible.

wooster commented 5 years ago

Given the above rects:

(lldb) expr [(UIScrollView *)scrollView TPKeyboardAvoiding_contentInsetForKeyboard]
(UIEdgeInsets) $26 = (top = 0, left = 0, bottom = -107, right = 0)

The offending line is:

keyboardRect.size.height - MAX((CGRectGetMaxY(keyboardRect) - CGRectGetMaxY(self.bounds)), 0)

The keyboard rect is converted from window coordinates to those of the scroll view:

(lldb) expr (CGRect)[(UIScrollView *)scrollView convertRect:(CGRect)[[(UIScrollView *)scrollView keyboardAvoidingState] keyboardRect] fromView:nil]
(CGRect) $37 = (origin = (x = -116, y = 572), size = (width = 1024, height = 55))

So keyboardRect is:

CGRectMake(-116, 572, 1024, 55)

So CGRectGetMaxY(keyboardRect) is:

(lldb) expr (CGFloat)CGRectGetMaxY(CGRectMake(-116, 572, 1024, 55))
(CGFloat) $38 = 627

And CGRectGetMaxY(self.bounds) is:

(lldb) expr (CGFloat)CGRectGetMaxY(CGRectMake(0, 138, 787,  327))
(CGFloat) $39 = 465

So:

55 - MAX(627 - 465, 0)
55 - MAX(162, 0)
55 - 162
-107

To avoid this, wrap another MAX(x, 0) to make sure the bottom inset isn't negative.