diff --git a/ios/observers/movement/observer/KeyboardMovementObserver+Lifecycle.swift b/ios/observers/movement/observer/KeyboardMovementObserver+Lifecycle.swift index cdbd63359b..9aff1408ee 100644 --- a/ios/observers/movement/observer/KeyboardMovementObserver+Lifecycle.swift +++ b/ios/observers/movement/observer/KeyboardMovementObserver+Lifecycle.swift @@ -29,6 +29,11 @@ public extension KeyboardMovementObserver { @objc func unmount() { isMounted = false + keyboardDidTask?.cancel() + keyboardDidTask = nil + notification = nil + removeKeyboardWatcher() + removeKVObserver() // swiftlint:disable:next notification_center_detachment NotificationCenter.default.removeObserver(self) } diff --git a/ios/observers/movement/observer/KeyboardMovementObserver+Listeners.swift b/ios/observers/movement/observer/KeyboardMovementObserver+Listeners.swift index 464eec73bb..75975ddcbf 100644 --- a/ios/observers/movement/observer/KeyboardMovementObserver+Listeners.swift +++ b/ios/observers/movement/observer/KeyboardMovementObserver+Listeners.swift @@ -6,6 +6,32 @@ // extension KeyboardMovementObserver { + private func emitKeyboardDidAppear(height: CGFloat, duration: Int) { + let progress = 1.0 + + onCancelAnimation() + onEvent("onKeyboardMoveEnd", height as NSNumber, progress as NSNumber, duration as NSNumber, tag) + onNotify("KeyboardController::keyboardDidShow", buildEventParams(height, duration, tag)) + + removeKeyboardWatcher() + setupKVObserver() + animation = nil + } + + private func emitKeyboardDidDisappear(duration: Int) { + onCancelAnimation() + onEvent("onKeyboardMoveEnd", 0 as NSNumber, 0, duration as NSNumber, tag) + onNotify("KeyboardController::keyboardDidHide", buildEventParams(0, duration, tag)) + + removeKeyboardWatcher() + animation = nil + } + + private func currentKeyboardHeight() -> CGFloat { + let (visibleKeyboardHeight, _) = keyboardTrackingView.view.frameTransitionInWindow + return max(CGFloat(visibleKeyboardHeight) - KeyboardAreaExtender.shared.offset, 0) + } + @objc func keyboardWillAppear(_ notification: Notification) { guard !UIResponder.isKeyboardPreloading else { return } @@ -63,17 +89,7 @@ extension KeyboardMovementObserver { tag = UIResponder.current.reactViewTag self.keyboardHeight = keyboardHeight - let height = self.keyboardHeight - // always limit progress to the maximum possible value - let progress = min(height / self.keyboardHeight, 1.0) - - onCancelAnimation() - onEvent("onKeyboardMoveEnd", height as NSNumber, progress as NSNumber, duration as NSNumber, tag) - onNotify("KeyboardController::keyboardDidShow", buildEventParams(height, duration, tag)) - - removeKeyboardWatcher() - setupKVObserver() - animation = nil + emitKeyboardDidAppear(height: self.keyboardHeight, duration: duration) NotificationCenter.default.post( name: .keyboardDidAppear, object: notification, userInfo: nil @@ -86,16 +102,14 @@ extension KeyboardMovementObserver { let (duration, _) = notification.keyboardMetaData() tag = UIResponder.current.reactViewTag - onCancelAnimation() - onEvent("onKeyboardMoveEnd", 0 as NSNumber, 0, duration as NSNumber, tag) - onNotify("KeyboardController::keyboardDidHide", buildEventParams(0, duration, tag)) - - removeKeyboardWatcher() - animation = nil + emitKeyboardDidDisappear(duration: duration) } - @objc func scheduleDidEvent(height: CGFloat, duration: CGFloat) { + @objc func scheduleDidEvent(height targetHeight: CGFloat, duration: CGFloat) { keyboardDidTask?.cancel() + keyboardDidEventID += 1 + let eventID = keyboardDidEventID + _ = targetHeight guard let notification = notification else { return @@ -103,10 +117,21 @@ extension KeyboardMovementObserver { let task = DispatchWorkItem { [weak self] in guard let self = self else { return } - if height > 0 { - self.keyboardDidAppear(notification) + guard self.isMounted, eventID == self.keyboardDidEventID else { return } + + let duration = self.duration + let currentHeight = self.currentKeyboardHeight() + self.tag = UIResponder.current.reactViewTag + + if currentHeight > 0 { + self.keyboardHeight = currentHeight + self.emitKeyboardDidAppear(height: currentHeight, duration: duration) + + NotificationCenter.default.post( + name: .keyboardDidAppear, object: notification, userInfo: nil + ) } else { - self.keyboardDidDisappear(notification) + self.emitKeyboardDidDisappear(duration: duration) } } diff --git a/ios/observers/movement/observer/KeyboardMovementObserver.swift b/ios/observers/movement/observer/KeyboardMovementObserver.swift index ae97d611a7..efd45c0e95 100644 --- a/ios/observers/movement/observer/KeyboardMovementObserver.swift +++ b/ios/observers/movement/observer/KeyboardMovementObserver.swift @@ -37,6 +37,7 @@ public class KeyboardMovementObserver: NSObject { // manual did events var notification: Notification? var keyboardDidTask: DispatchWorkItem? + var keyboardDidEventID: UInt = 0 @objc public init( handler: @escaping (NSString, NSNumber, NSNumber, NSNumber, NSNumber) -> Void,