RNCSafeAreaView.m 2.5KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // Simplified version of https://github.com/facebook/react-native/blob/master/React/Views/SafeAreaView/RCTSafeAreaView.m
  2. #import "RNCSafeAreaView.h"
  3. #import <React/RCTBridge.h>
  4. #import <React/RCTUIManager.h>
  5. static BOOL UIEdgeInsetsEqualToEdgeInsetsWithThreshold(UIEdgeInsets insets1, UIEdgeInsets insets2, CGFloat threshold) {
  6. return
  7. ABS(insets1.left - insets2.left) <= threshold &&
  8. ABS(insets1.right - insets2.right) <= threshold &&
  9. ABS(insets1.top - insets2.top) <= threshold &&
  10. ABS(insets1.bottom - insets2.bottom) <= threshold;
  11. }
  12. @implementation RNCSafeAreaView
  13. {
  14. UIEdgeInsets _currentSafeAreaInsets;
  15. }
  16. - (BOOL)isSupportedByOS
  17. {
  18. return [self respondsToSelector:@selector(safeAreaInsets)];
  19. }
  20. - (UIEdgeInsets)realOrEmulateSafeAreaInsets
  21. {
  22. #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
  23. if (self.isSupportedByOS) {
  24. if (@available(iOS 11.0, *)) {
  25. return self.safeAreaInsets;
  26. }
  27. }
  28. #endif
  29. return self.emulatedSafeAreaInsets;
  30. }
  31. - (UIEdgeInsets)emulatedSafeAreaInsets
  32. {
  33. UIViewController* vc = self.reactViewController;
  34. if (!vc) {
  35. return UIEdgeInsetsZero;
  36. }
  37. CGFloat topLayoutOffset = vc.topLayoutGuide.length;
  38. CGFloat bottomLayoutOffset = vc.bottomLayoutGuide.length;
  39. CGRect safeArea = vc.view.bounds;
  40. safeArea.origin.y += topLayoutOffset;
  41. safeArea.size.height -= topLayoutOffset + bottomLayoutOffset;
  42. CGRect localSafeArea = [vc.view convertRect:safeArea toView:self];
  43. UIEdgeInsets safeAreaInsets = UIEdgeInsetsMake(0, 0, 0, 0);
  44. if (CGRectGetMinY(localSafeArea) > CGRectGetMinY(self.bounds)) {
  45. safeAreaInsets.top = CGRectGetMinY(localSafeArea) - CGRectGetMinY(self.bounds);
  46. }
  47. if (CGRectGetMaxY(localSafeArea) < CGRectGetMaxY(self.bounds)) {
  48. safeAreaInsets.bottom = CGRectGetMaxY(self.bounds) - CGRectGetMaxY(localSafeArea);
  49. }
  50. return safeAreaInsets;
  51. }
  52. - (void)safeAreaInsetsDidChange
  53. {
  54. [self invalidateSafeAreaInsets];
  55. }
  56. - (void)invalidateSafeAreaInsets
  57. {
  58. UIEdgeInsets safeAreaInsets = [self realOrEmulateSafeAreaInsets];
  59. if (UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale())) {
  60. return;
  61. }
  62. _currentSafeAreaInsets = safeAreaInsets;
  63. self.onInsetsChange(@{
  64. @"insets": @{
  65. @"top": @(safeAreaInsets.top),
  66. @"right": @(safeAreaInsets.right),
  67. @"bottom": @(safeAreaInsets.bottom),
  68. @"left": @(safeAreaInsets.left),
  69. }
  70. });
  71. }
  72. - (void)layoutSubviews
  73. {
  74. [super layoutSubviews];
  75. if (!self.isSupportedByOS) {
  76. [self invalidateSafeAreaInsets];
  77. }
  78. }
  79. @end