1#import "RNCSafeAreaView.h" 2 3#import <React/RCTBridge.h> 4#import <React/RCTUIManager.h> 5 6#import "RNCSafeAreaProvider.h" 7#import "RNCSafeAreaUtils.h" 8#import "RNCSafeAreaViewEdges.h" 9#import "RNCSafeAreaViewLocalData.h" 10#import "RNCSafeAreaViewMode.h" 11 12@implementation RNCSafeAreaView { 13 __weak RCTBridge *_bridge; 14 UIEdgeInsets _currentSafeAreaInsets; 15 RNCSafeAreaViewMode _mode; 16 RNCSafeAreaViewEdges _edges; 17 __weak RNCSafeAreaProvider *_Nullable _providerView; 18} 19 20- (instancetype)initWithBridge:(RCTBridge *)bridge 21{ 22 if (self = [super initWithFrame:CGRectZero]) { 23 _bridge = bridge; 24 // Defaults 25 _mode = RNCSafeAreaViewModePadding; 26 _edges = RNCSafeAreaViewEdgesMake( 27 RNCSafeAreaViewEdgeModeOff, RNCSafeAreaViewEdgeModeOff, RNCSafeAreaViewEdgeModeOff, RNCSafeAreaViewEdgeModeOff); 28 } 29 30 return self; 31} 32 33RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)decoder) 34RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame) 35 36- (NSString *)description 37{ 38 NSString *superDescription = [super description]; 39 40 // Cutting the last `>` character. 41 if (superDescription.length > 0 && [superDescription characterAtIndex:superDescription.length - 1] == '>') { 42 superDescription = [superDescription substringToIndex:superDescription.length - 1]; 43 } 44 45 return [NSString stringWithFormat:@"%@; RNCSafeAreaInsets = %@; appliedRNCSafeAreaInsets = %@>", 46 superDescription, 47 NSStringFromUIEdgeInsets(_providerView.safeAreaInsets), 48 NSStringFromUIEdgeInsets(_currentSafeAreaInsets)]; 49} 50 51- (void)didMoveToWindow 52{ 53 UIView *previousProviderView = _providerView; 54 _providerView = [self findNearestProvider]; 55 56 [self invalidateSafeAreaInsets]; 57 58 if (previousProviderView != _providerView) { 59 if (previousProviderView != nil) { 60 [NSNotificationCenter.defaultCenter removeObserver:self name:RNCSafeAreaDidChange object:previousProviderView]; 61 } 62 63 if (_providerView != nil) { 64 [NSNotificationCenter.defaultCenter addObserver:self 65 selector:@selector(safeAreaProviderInsetsDidChange:) 66 name:RNCSafeAreaDidChange 67 object:_providerView]; 68 } 69 } 70} 71 72- (void)safeAreaProviderInsetsDidChange:(NSNotification *)notification 73{ 74 [self invalidateSafeAreaInsets]; 75} 76 77- (void)invalidateSafeAreaInsets 78{ 79 if (_providerView == nil) { 80 return; 81 } 82 UIEdgeInsets safeAreaInsets = _providerView.safeAreaInsets; 83 84 if (UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale())) { 85 return; 86 } 87 88 _currentSafeAreaInsets = safeAreaInsets; 89 [self updateLocalData]; 90} 91 92- (nullable RNCSafeAreaProvider *)findNearestProvider 93{ 94 UIView *current = self.reactSuperview; 95 while (current != nil) { 96 if ([current isKindOfClass:RNCSafeAreaProvider.class]) { 97 return (RNCSafeAreaProvider *)current; 98 } 99 current = current.reactSuperview; 100 } 101 return nil; 102} 103 104- (void)updateLocalData 105{ 106 if (_providerView == nil) { 107 return; 108 } 109 RNCSafeAreaViewLocalData *localData = [[RNCSafeAreaViewLocalData alloc] initWithInsets:_currentSafeAreaInsets 110 mode:_mode 111 edges:_edges]; 112 [_bridge.uiManager setLocalData:localData forView:self]; 113} 114 115- (void)setMode:(RNCSafeAreaViewMode)mode 116{ 117 _mode = mode; 118 [self updateLocalData]; 119} 120 121- (void)setEdges:(RNCSafeAreaViewEdges)edges 122{ 123 _edges = edges; 124 [self updateLocalData]; 125} 126 127@end 128