Skip to content

Commit

Permalink
fix: don't jump to height when iOS keyboard is rapidly opened/closed
Browse files Browse the repository at this point in the history
The interactive dismissal logic would get tripped up if the keyboard was
rapidly opened and closed, which can happen if a hardware keyboard is
used and the autosuggest dock appears and then disappears when the on
screen keyboard is opened.

Fixes software-mansion#6727.
  • Loading branch information
mhoran committed Nov 28, 2024
1 parent 8895f74 commit ddefb46
Showing 1 changed file with 12 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ typedef NS_ENUM(NSUInteger, KeyboardState) {
OPEN = 2,
CLOSING = 3,
CLOSED = 4,
OPENING_INTERACTIVE = 6
};

@implementation REAKeyboardEventObserver {
Expand All @@ -25,6 +26,7 @@ @implementation REAKeyboardEventObserver {
float _targetKeyboardHeight;
REAUIView *_keyboardView;
bool _isKeyboardObserverAttached;
bool _isInteractiveDismissalCanceled;
}

- (instancetype)init
Expand All @@ -35,6 +37,7 @@ - (instancetype)init
_state = UNKNOWN;
_animationStartTimestamp = 0;
_isKeyboardObserverAttached = false;
_isInteractiveDismissalCanceled = false;
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];

[notificationCenter addObserver:self
Expand Down Expand Up @@ -213,20 +216,21 @@ - (void)keyboardWillChangeFrame:(NSNotification *)notification
}

/*
This may seem a bit confusing, but usually, the state should be either OPENED or CLOSED.
However, if it shows as OPENING, it means that the interactive dismissal was canceled.
If interactive dismissal was canceled, beginFrame may not reflect the latest position
of the keyboard. We need to check whether interactive dismissal was canceled, get the
the latest frame directly from the keyboardView, then reset the flag.
*/
bool isInteractiveMode = _state == OPENING && _isKeyboardObserverAttached;
bool isInteractiveDismissalCanceled = _isInteractiveDismissalCanceled;
auto keyboardView = [self getKeyboardView];
if (_state == CLOSING) {
_targetKeyboardHeight = 0;
} else if (isInteractiveMode) {
// This condition can be met after canceling interactive dismissal.
} else if (isInteractiveDismissalCanceled) {
_initialKeyboardHeight = windowSize.height - keyboardView.frame.origin.y;
_isInteractiveDismissalCanceled = false;
}

bool hasKeyboardAnimation = [self hasAnyAnimation:keyboardView];
if (hasKeyboardAnimation || isInteractiveMode) {
if (hasKeyboardAnimation || isInteractiveDismissalCanceled) {
_measuringView.frame = CGRectMake(0, -1, 0, _initialKeyboardHeight);
[UIView animateWithDuration:animationDuration
animations:^{
Expand Down Expand Up @@ -338,8 +342,10 @@ - (void)updateKeyboardHeightDuringInteractiveDismiss:(CGPoint)oldKeyboardFrame
return;
}
float visibleKeyboardHeight = windowHeight - (newKeyboardFrame.y - keyboardHeight / 2);
_isInteractiveDismissalCanceled = false;
if (oldKeyboardFrame.y > newKeyboardFrame.y) {
_state = OPENING;
_isInteractiveDismissalCanceled = true;
} else if (oldKeyboardFrame.y < newKeyboardFrame.y) {
_state = CLOSING;
}
Expand Down

0 comments on commit ddefb46

Please sign in to comment.