123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- // Simplified version of https://github.com/facebook/react-native/blob/master/React/Views/SafeAreaView/RCTSafeAreaView.m
-
- #import "RNCSafeAreaView.h"
-
- #import <React/RCTBridge.h>
- #import <React/RCTUIManager.h>
-
- static BOOL UIEdgeInsetsEqualToEdgeInsetsWithThreshold(UIEdgeInsets insets1, UIEdgeInsets insets2, CGFloat threshold) {
- return
- ABS(insets1.left - insets2.left) <= threshold &&
- ABS(insets1.right - insets2.right) <= threshold &&
- ABS(insets1.top - insets2.top) <= threshold &&
- ABS(insets1.bottom - insets2.bottom) <= threshold;
- }
-
- @implementation RNCSafeAreaView
- {
- UIEdgeInsets _currentSafeAreaInsets;
- CGRect _currentFrame;
- BOOL _initialInsetsSent;
- }
-
- - (BOOL)isSupportedByOS
- {
- return [self respondsToSelector:@selector(safeAreaInsets)];
- }
-
- - (UIEdgeInsets)realOrEmulateSafeAreaInsets
- {
- #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
- if (self.isSupportedByOS) {
- if (@available(iOS 11.0, *)) {
- return self.safeAreaInsets;
- }
- }
- #endif
- return self.emulatedSafeAreaInsets;
- }
-
- - (UIEdgeInsets)emulatedSafeAreaInsets
- {
- UIViewController* vc = self.reactViewController;
-
- if (!vc) {
- return UIEdgeInsetsZero;
- }
-
- CGFloat topLayoutOffset = vc.topLayoutGuide.length;
- CGFloat bottomLayoutOffset = vc.bottomLayoutGuide.length;
- CGRect safeArea = vc.view.bounds;
- safeArea.origin.y += topLayoutOffset;
- safeArea.size.height -= topLayoutOffset + bottomLayoutOffset;
- CGRect localSafeArea = [vc.view convertRect:safeArea toView:self];
- UIEdgeInsets safeAreaInsets = UIEdgeInsetsMake(0, 0, 0, 0);
- if (CGRectGetMinY(localSafeArea) > CGRectGetMinY(self.bounds)) {
- safeAreaInsets.top = CGRectGetMinY(localSafeArea) - CGRectGetMinY(self.bounds);
- }
- if (CGRectGetMaxY(localSafeArea) < CGRectGetMaxY(self.bounds)) {
- safeAreaInsets.bottom = CGRectGetMaxY(self.bounds) - CGRectGetMaxY(localSafeArea);
- }
-
- return safeAreaInsets;
- }
-
- - (void)safeAreaInsetsDidChange
- {
- [self invalidateSafeAreaInsets];
- }
-
- - (void)invalidateSafeAreaInsets
- {
- // This gets called before the view size is set by react-native so
- // make sure to wait so we don't set wrong insets to JS.
- if (CGSizeEqualToSize(self.frame.size, CGSizeZero)) {
- return;
- }
-
- UIEdgeInsets safeAreaInsets = [self realOrEmulateSafeAreaInsets];
- CGRect frame = [self convertRect:self.bounds toView:nil];
-
- if (
- _initialInsetsSent &&
- UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale()) &&
- CGRectEqualToRect(frame, _currentFrame)
- ) {
- return;
- }
-
- _initialInsetsSent = YES;
- _currentSafeAreaInsets = safeAreaInsets;
- _currentFrame = frame;
-
- 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),
- },
- });
- }
-
- - (void)layoutSubviews
- {
- [super layoutSubviews];
-
- [self invalidateSafeAreaInsets];
- }
-
- @end
|