Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions ios/RNCChangeEvent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#import <Foundation/Foundation.h>
#import <React/RCTEventDispatcherProtocol.h>

@interface RNCChangeEvent : NSObject <RCTEvent>

- (instancetype)initWithEventName:(NSString *)eventName
reactTag:(NSNumber *)reactTag
insets:(UIEdgeInsets)insets
frame:(CGRect)frame
coalescingKey:(uint16_t)coalescingKey NS_DESIGNATED_INITIALIZER;

@end
87 changes: 87 additions & 0 deletions ios/RNCChangeEvent.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#import "RNCChangeEvent.h"
#import <React/RCTAssert.h>

@implementation RNCChangeEvent {
UIEdgeInsets _insets;
CGRect _frame;
uint16_t _coalescingKey;
}

@synthesize eventName = _eventName;
@synthesize viewTag = _viewTag;

- (instancetype)initWithEventName:(NSString *)eventName
reactTag:(NSNumber *)reactTag
insets:(UIEdgeInsets)insets
frame:(CGRect)frame
coalescingKey:(uint16_t)coalescingKey
{
RCTAssertParam(reactTag);

if ((self = [super init])) {
_eventName = [eventName copy];
_viewTag = reactTag;
_frame = frame;
_insets = insets;
_coalescingKey = coalescingKey;
}

return self;
}

RCT_NOT_IMPLEMENTED(-(instancetype)init)

- (uint16_t)coalescingKey
{
return _coalescingKey;
}

- (NSDictionary *)body
{
NSDictionary *body = @{
@"insets" : @{
@"top" : @(_insets.top),
@"right" : @(_insets.right),
@"bottom" : @(_insets.bottom),
@"left" : @(_insets.left),
},
@"frame" : @{
@"x" : @(_frame.origin.x),
@"y" : @(_frame.origin.y),
@"width" : @(_frame.size.width),
@"height" : @(_frame.size.height),
},
};

return body;
}

- (BOOL)canCoalesce
{
return YES;
}

- (RNCChangeEvent *)coalesceWithEvent:(RNCChangeEvent *)newEvent
{
return newEvent;
}

+ (NSString *)moduleDotMethod
{
return @"RCTEventEmitter.receiveEvent";
}

- (NSArray *)arguments
{
return @[ self.viewTag, RCTNormalizeInputEventName(self.eventName), [self body] ];
}

/*
Not sure if this is needed as eventName is passed in arguments
- (NSString *)eventName
{
return _eventName;
}
*/

@end
6 changes: 6 additions & 0 deletions ios/RNCSafeAreaProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@
#import <AppKit/AppKit.h>
#endif

#import <React/RCTEventDispatcherProtocol.h>
#import <React/RCTView.h>

NS_ASSUME_NONNULL_BEGIN

@interface RNCSafeAreaProvider : RCTView

- (instancetype)initWithEventDispatcher:(id<RCTEventDispatcherProtocol>)eventDispatcher NS_DESIGNATED_INITIALIZER;

// NOTE: currently these event props are only declared so we can export the
// event names to JS - we don't call the blocks directly because events
// need to be coalesced before sending, for performance reasons.
@property (nonatomic, copy) RCTBubblingEventBlock onInsetsChange;

@end
Expand Down
54 changes: 37 additions & 17 deletions ios/RNCSafeAreaProvider.m
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
#import "RNCSafeAreaProvider.h"

#import <React/RCTEventDispatcher.h>
#import <React/RCTBridge.h>
#import <React/RCTUIManager.h>
#import "RCTUIManagerObserverCoordinator.h"
#import "RNCSafeAreaUtils.h"
#import "RNCChangeEvent.h"

@interface RNCSafeAreaProvider () <RCTUIManagerObserver>

@end

@implementation RNCSafeAreaProvider {
id<RCTEventDispatcherProtocol> _eventDispatcher;
UIEdgeInsets _currentSafeAreaInsets;
CGRect _currentFrame;
BOOL _initialInsetsSent;
uint16_t _coalescingKey;
}

- (instancetype)init
- (instancetype)initWithEventDispatcher:(id<RCTEventDispatcherProtocol>)eventDispatcher
{
if ((self = [super init])) {
RCTAssertParam(eventDispatcher);

if ((self = [super initWithFrame:CGRectZero])) {
#if !TARGET_OS_TV && !TARGET_OS_OSX

_eventDispatcher = eventDispatcher;

[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(invalidateSafeAreaInsets)
name:UIKeyboardDidShowNotification
Expand Down Expand Up @@ -58,6 +72,7 @@ - (void)invalidateSafeAreaInsets
safeAreaInsets = NSEdgeInsetsZero;
}
#endif

CGRect frame = [self convertRect:self.bounds toView:RNCParentViewController(self).view];

if (_initialInsetsSent &&
Expand All @@ -69,27 +84,23 @@ - (void)invalidateSafeAreaInsets
CGRectEqualToRect(frame, _currentFrame)) {
return;
}

_initialInsetsSent = YES;
_currentSafeAreaInsets = safeAreaInsets;
_currentFrame = frame;

[NSNotificationCenter.defaultCenter postNotificationName:RNCSafeAreaDidChange object:self userInfo:nil];

self.onInsetsChange(@{
@"insets" : @{
@"top" : @(safeAreaInsets.top),
@"right" : @(safeAreaInsets.right),
@"bottom" : @(safeAreaInsets.bottom),
@"left" : @(safeAreaInsets.left),
},
@"frame" : @{
@"x" : @(frame.origin.x),
@"y" : @(frame.origin.y),
@"width" : @(frame.size.width),
@"height" : @(frame.size.height),
},
});
// There's currently only 1 event name "onInsetsChange", so the _coalescingKey doesn't needs to be incremented
// Increment _coalescingKey if safeAreaInsets and frame are sent as separate events
RNCChangeEvent *changeEvent = [[RNCChangeEvent alloc] initWithEventName:@"onInsetsChange"
reactTag:self.reactTag
insets:safeAreaInsets
frame:frame
coalescingKey:_coalescingKey];


[_eventDispatcher sendEvent:changeEvent];
}

- (void)layoutSubviews
Expand All @@ -99,4 +110,13 @@ - (void)layoutSubviews
[self invalidateSafeAreaInsets];
}

- (void)dealloc
{
[_eventDispatcher.bridge.uiManager.observerCoordinator removeObserver:self];
}


RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)

@end
2 changes: 1 addition & 1 deletion ios/RNCSafeAreaProviderManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ - (UIView *)view
- (NSView *)view
#endif
{
return [RNCSafeAreaProvider new];
return [[RNCSafeAreaProvider alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
}

@end
6 changes: 6 additions & 0 deletions ios/RNSafeAreaContext.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
0C7844F027C02D03001807FB /* RNCSafeAreaProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C7844ED27C02D03001807FB /* RNCSafeAreaProvider.m */; };
AA53A9EE2A321C01009AB3B2 /* RNCSafeAreaViewEdgeModes.m in Sources */ = {isa = PBXBuildFile; fileRef = AA53A9ED2A321C01009AB3B2 /* RNCSafeAreaViewEdgeModes.m */; };
C923EDBC220C2C1A00D3100F /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C923EDBB220C2C1A00D3100F /* SystemConfiguration.framework */; };
D697AA982D6F1D0A009C6433 /* RNCChangeEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D697AA972D6F1D08009C6433 /* RNCChangeEvent.m */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand Down Expand Up @@ -59,6 +60,8 @@
AA53A9EC2A321C01009AB3B2 /* RNCSafeAreaViewEdgeModes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNCSafeAreaViewEdgeModes.h; sourceTree = "<group>"; };
AA53A9ED2A321C01009AB3B2 /* RNCSafeAreaViewEdgeModes.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNCSafeAreaViewEdgeModes.m; sourceTree = "<group>"; };
C923EDBB220C2C1A00D3100F /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
D697AA962D6F1CE5009C6433 /* RNCChangeEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNCChangeEvent.h; sourceTree = "<group>"; };
D697AA972D6F1D08009C6433 /* RNCChangeEvent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNCChangeEvent.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -84,6 +87,8 @@
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
D697AA972D6F1D08009C6433 /* RNCChangeEvent.m */,
D697AA962D6F1CE5009C6433 /* RNCChangeEvent.h */,
AA53A9EC2A321C01009AB3B2 /* RNCSafeAreaViewEdgeModes.h */,
AA53A9ED2A321C01009AB3B2 /* RNCSafeAreaViewEdgeModes.m */,
0C7844EE27C02D03001807FB /* Fabric */,
Expand Down Expand Up @@ -183,6 +188,7 @@
0C7844E827C02CEE001807FB /* RNCSafeAreaView.m in Sources */,
0C7844E627C02CEE001807FB /* RNCSafeAreaViewEdges.m in Sources */,
0C7844E527C02CEE001807FB /* RNCSafeAreaViewManager.m in Sources */,
D697AA982D6F1D0A009C6433 /* RNCChangeEvent.m in Sources */,
0C7844EF27C02D03001807FB /* RNCSafeAreaContext.mm in Sources */,
0C7844E127C02CEE001807FB /* RNCSafeAreaViewLocalData.m in Sources */,
0C7844E227C02CEE001807FB /* RNCSafeAreaViewMode.m in Sources */,
Expand Down
2 changes: 2 additions & 0 deletions src/SafeAreaContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ export function SafeAreaProvider({
nativeEvent: { frame: nextFrame, insets: nextInsets },
} = event;

console.log('onInsetsChange', nextInsets);

setFrame((curFrame) => {
if (
// Backwards compat with old native code that won't send frame.
Expand Down