react-native/React/Modules/RCTKeyboardObserver.m

122 lines
3.5 KiB
Objective-C

/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTKeyboardObserver.h"
#import "RCTEventDispatcher.h"
static NSDictionary *RCTParseKeyboardNotification(NSNotification *notification);
@implementation RCTKeyboardObserver
RCT_EXPORT_MODULE()
- (void)startObserving
{
#if !TARGET_OS_TV
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
#define ADD_KEYBOARD_HANDLER(NAME, SELECTOR) \
[nc addObserver:self selector:@selector(SELECTOR:) name:NAME object:nil]
ADD_KEYBOARD_HANDLER(UIKeyboardWillShowNotification, keyboardWillShow);
ADD_KEYBOARD_HANDLER(UIKeyboardDidShowNotification, keyboardDidShow);
ADD_KEYBOARD_HANDLER(UIKeyboardWillHideNotification, keyboardWillHide);
ADD_KEYBOARD_HANDLER(UIKeyboardDidHideNotification, keyboardDidHide);
ADD_KEYBOARD_HANDLER(UIKeyboardWillChangeFrameNotification, keyboardWillChangeFrame);
ADD_KEYBOARD_HANDLER(UIKeyboardDidChangeFrameNotification, keyboardDidChangeFrame);
#undef ADD_KEYBOARD_HANDLER
#endif
}
- (NSArray<NSString *> *)supportedEvents
{
return @[@"keyboardWillShow",
@"keyboardDidShow",
@"keyboardWillHide",
@"keyboardDidHide",
@"keyboardWillChangeFrame",
@"keyboardDidChangeFrame"];
}
- (void)stopObserving
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
// Bridge might be already invalidated by the time the keyboard is about to be dismissed.
// This might happen, for example, when reload from the packager is performed.
// Thus we need to check against nil here.
#define IMPLEMENT_KEYBOARD_HANDLER(EVENT) \
- (void)EVENT:(NSNotification *)notification \
{ \
if (!self.bridge) { \
return; \
} \
[self sendEventWithName:@#EVENT \
body:RCTParseKeyboardNotification(notification)]; \
}
IMPLEMENT_KEYBOARD_HANDLER(keyboardWillShow)
IMPLEMENT_KEYBOARD_HANDLER(keyboardDidShow)
IMPLEMENT_KEYBOARD_HANDLER(keyboardWillHide)
IMPLEMENT_KEYBOARD_HANDLER(keyboardDidHide)
IMPLEMENT_KEYBOARD_HANDLER(keyboardWillChangeFrame)
IMPLEMENT_KEYBOARD_HANDLER(keyboardDidChangeFrame)
@end
NS_INLINE NSDictionary *RCTRectDictionaryValue(CGRect rect)
{
return @{
@"screenX": @(rect.origin.x),
@"screenY": @(rect.origin.y),
@"width": @(rect.size.width),
@"height": @(rect.size.height),
};
}
static NSString *RCTAnimationNameForCurve(UIViewAnimationCurve curve)
{
switch (curve) {
case UIViewAnimationCurveEaseIn:
return @"easeIn";
case UIViewAnimationCurveEaseInOut:
return @"easeInEaseOut";
case UIViewAnimationCurveEaseOut:
return @"easeOut";
case UIViewAnimationCurveLinear:
return @"linear";
default:
return @"keyboard";
}
}
static NSDictionary *RCTParseKeyboardNotification(NSNotification *notification)
{
#if TARGET_OS_TV
return @{};
#else
NSDictionary *userInfo = notification.userInfo;
CGRect beginFrame = [userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect endFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
return @{
@"startCoordinates": RCTRectDictionaryValue(beginFrame),
@"endCoordinates": RCTRectDictionaryValue(endFrame),
@"duration": @(duration * 1000.0), // ms
@"easing": RCTAnimationNameForCurve(curve),
};
#endif
}