Skip to content

Commit

Permalink
fix: no random onStart/onEnd events during interactive keyboard dismi…
Browse files Browse the repository at this point in the history
…ssal
  • Loading branch information
kirillzyusko committed Jan 14, 2025
1 parent 5cbfc48 commit c1fd2b9
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 23 deletions.
7 changes: 4 additions & 3 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
- (x) text input grow -> can not make interactive gesture (Optional(424.6666666666667) 424.66666666666674) - maybe because of frequent conversions to CGFloat? <- fixed via rounding
- 1 show after interactive - keyboard height is 386
- 2 show after interactive - iav is not attached again
- 3 two events get dispatched when we remove iav in onInteractive - (dispatch `shouldIgnoreKeyboardEvents` in .hide (KEA)? - doesn't work because swizzle calls .hide when keyboard appear)
- (x) 3 two events get dispatched when we remove iav in onInteractive - (dispatch `shouldIgnoreKeyboardEvents` in .hide (KEA)? - doesn't work because swizzle calls .hide when keyboard appear)
- (x) 4 two events get dispatched after 2nd onInteractive (fix with pan gesture responder - when it's active ignore plain keyboard events)

:: call actual code for hide only once
::: dispatch ignore event when we actually hide iav (will fix 3)
:: (x) call actual code for hide only once
::: (x) dispatch ignore event when we actually hide iav (will fix 3)
::: (add `lastOffset`) - will fix 1 <- last time when I added it was resetting somehow, need to figure out where and why exactly
::: add code in `keyboardDidAppear` in KAE to increase/attach iav again (will fix 2)
9 changes: 7 additions & 2 deletions ios/interactive/InvisibleInputAccessoryView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import Foundation
import UIKit

public class InvisibleInputAccessoryView: UIView {
var isShown = true

override init(frame: CGRect) {
super.init(frame: frame)
setupView()
Expand Down Expand Up @@ -37,6 +39,9 @@ public class InvisibleInputAccessoryView: UIView {
}

public func hide() {
guard isShown else { return }
isShown = false
print("hide")
updateHeight(to: 0.0)
superview?.layoutIfNeeded()
}
Expand All @@ -48,8 +53,8 @@ public class InvisibleInputAccessoryView: UIView {
private func setupView() {
isUserInteractionEnabled = false
// TODO: Set the background color to transparent
// backgroundColor = UIColor.red
backgroundColor = .clear
backgroundColor = UIColor.red
// backgroundColor = .clear
autoresizingMask = .flexibleHeight
}
}
9 changes: 8 additions & 1 deletion ios/interactive/KeyboardAreaExtender.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,14 @@ class KeyboardAreaExtender: NSObject {
}

public func hide() {
currentInputAccessoryView?.hide()
if (currentInputAccessoryView?.isShown ?? false) {
print("hide iav")
NotificationCenter.default.post(
name: .shouldIgnoreKeyboardEvents, object: nil, userInfo: ["ignore": true]
)
currentInputAccessoryView?.hide()
}
print("ignore hide")
}

public func updateHeight(_ to: CGFloat, _ nativeID: String) {
Expand Down
14 changes: 12 additions & 2 deletions ios/observers/KeyboardEventsIgnorer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,20 @@

import Foundation

class KeyboardEventsIgnorer {
@objc(KeyboardEventsIgnorer)
public class KeyboardEventsIgnorer : NSObject {
@objc public static let shared = KeyboardEventsIgnorer()

var shouldIgnoreKeyboardEvents = false
@objc public var isInteractiveGesture = false

public var shouldIgnore : Bool {
print("KeyboardEventsIgnorer \(shouldIgnoreKeyboardEvents) \(isInteractiveGesture)")
return shouldIgnoreKeyboardEvents || isInteractiveGesture
}

init() {
override init() {
super.init()
NotificationCenter.default.addObserver(
self,
selector: #selector(handleIgnoreKeyboardEventsNotification),
Expand Down
20 changes: 10 additions & 10 deletions ios/observers/KeyboardMovementObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ public class KeyboardMovementObserver: NSObject {
private var tag: NSNumber = -1
private var animation: KeyboardAnimation?
private var didShowDeadline: Int64 = 0
// external class instances
private let eventsIgnorer = KeyboardEventsIgnorer()

@objc public init(
handler: @escaping (NSString, NSNumber, NSNumber, NSNumber, NSNumber) -> Void,
Expand Down Expand Up @@ -160,16 +158,18 @@ public class KeyboardMovementObserver: NSObject {
}

prevKeyboardPosition = position
// TODO: needs here? Why in onStart/onEnd after interactive gesture we get keyboard height as 386?
KeyboardAreaExtender.shared.hide()
///

onEvent(
"onKeyboardMoveInteractive",
position as NSNumber,
position / CGFloat(keyboardHeight) as NSNumber,
-1,
tag
)

// TODO: needs here? Why in onStart/onEnd after interactive gesture we get keyboard height as 386?
KeyboardAreaExtender.shared.hide()
///
}
}

Expand All @@ -180,7 +180,7 @@ public class KeyboardMovementObserver: NSObject {
}

@objc func keyboardWillAppear(_ notification: Notification) {
guard !eventsIgnorer.shouldIgnoreKeyboardEvents else { return }
guard !KeyboardEventsIgnorer.shared.shouldIgnore else { return }
print("keyboardWillAppear \(Date.currentTimeStamp)")
let (duration, frame) = notification.keyboardMetaData()
if let keyboardFrame = frame {
Expand All @@ -203,7 +203,7 @@ public class KeyboardMovementObserver: NSObject {
}

@objc func keyboardWillDisappear(_ notification: Notification) {
guard !eventsIgnorer.shouldIgnoreKeyboardEvents else { return }
guard !KeyboardEventsIgnorer.shared.shouldIgnore else { return }
print("keyboardWillDisappear \(Date.currentTimeStamp)")
let (duration, _) = notification.keyboardMetaData()
tag = UIResponder.current.reactViewTag
Expand All @@ -228,8 +228,8 @@ public class KeyboardMovementObserver: NSObject {
tag = UIResponder.current.reactViewTag
self.keyboardHeight = keyboardHeight

guard !eventsIgnorer.shouldIgnoreKeyboardEvents else {
eventsIgnorer.shouldIgnoreKeyboardEvents = false
guard !KeyboardEventsIgnorer.shared.shouldIgnore else {
KeyboardEventsIgnorer.shared.shouldIgnoreKeyboardEvents = false
return
}

Expand All @@ -255,7 +255,7 @@ public class KeyboardMovementObserver: NSObject {
}

@objc func keyboardDidDisappear(_ notification: Notification) {
guard !eventsIgnorer.shouldIgnoreKeyboardEvents else { return }
guard !KeyboardEventsIgnorer.shared.shouldIgnore else { return }
print("keyboardDidDisappear \(Date.currentTimeStamp)")
let (duration, _) = notification.keyboardMetaData()
tag = UIResponder.current.reactViewTag
Expand Down
7 changes: 4 additions & 3 deletions ios/swizzling/UIResponderSwizzle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ extension UIResponder {
// Add your custom behavior here
print("Performing custom actions before the original resignFirstResponder")

if let textField = self as? TextInput {
(textField.inputAccessoryView as? InvisibleInputAccessoryView)?.hide()
}
KeyboardAreaExtender.shared.hide()
// if let textField = self as? TextInput {
// (textField.inputAccessoryView as? InvisibleInputAccessoryView)?.hide()
// }

// Postpone execution of the original resignFirstResponder
DispatchQueue.main.asyncAfter(deadline: .now() + UIUtils.nextFrame) {
Expand Down
36 changes: 34 additions & 2 deletions ios/views/KeyboardGestureAreaManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,14 @@ - (UIView *)view

// MARK: View
#ifdef RCT_NEW_ARCH_ENABLED
@interface KeyboardGestureArea () <RCTKeyboardGestureAreaViewProtocol>
@end
@interface KeyboardGestureArea () <RCTKeyboardGestureAreaViewProtocol, UIGestureRecognizerDelegate>
#else
@interface KeyboardGestureArea () <UIGestureRecognizerDelegate>
#endif
@end

@implementation KeyboardGestureArea {
UIPanGestureRecognizer *_panGestureRecognizer;
}

#ifdef RCT_NEW_ARCH_ENABLED
Expand All @@ -81,6 +84,7 @@ + (void)load
- (instancetype)init
{
if (self = [super init]) {
[self setupGestureRecognizers];
}
return self;
}
Expand All @@ -89,6 +93,7 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
{
self = [super initWithFrame:CGRectZero];
if (self) {
[self setupGestureRecognizers];
}

return self;
Expand All @@ -100,6 +105,33 @@ - (void)dealloc
[[KeyboardOffsetProvider shared] removeOffsetForTextInputNativeID:_textInputNativeID];
}

// MARK: Gesture Recognizers
- (void)setupGestureRecognizers
{
_panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
_panGestureRecognizer.delegate = self; // Set delegate to enable simultaneous recognition
[self addGestureRecognizer:_panGestureRecognizer];
}

- (void)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
[KeyboardEventsIgnorer shared].isInteractiveGesture = YES;
}
if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
NSLog(@"set to false");
[KeyboardEventsIgnorer shared].isInteractiveGesture = NO;
}

}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
// Allow simultaneous gesture recognition
return YES;
}

// MARK: lifecycle methods
- (void)didMoveToSuperview
{
Expand Down

0 comments on commit c1fd2b9

Please sign in to comment.