33 次程式碼提交

作者 SHA1 備註 提交日期
  cani1see 5d5bc2b268 Merge remote-tracking branch 'origin/master' into unjetify 4 年之前
  Janic Duplessis f126189030 Add react-native-safe-area-view example 4 年之前
  Janic Duplessis 411672821b 1.0.2 4 年之前
  Janic Duplessis 7a7935f78b Bring back SafeAreaContext for better compat with 0.x 4 年之前
  Janic Duplessis 54961270aa 1.0.1 4 年之前
  Janic Duplessis cf69c90c09 Fix flipper package 4 年之前
  Satyajit Sahoo 72774fffd4
fix: don't use .web extension (#77) 4 年之前
  Janic Duplessis 67616426be Add native stack example 4 年之前
  Janic Duplessis 0ccc32c5dc Add React Navigation 5 example 4 年之前
  Janic Duplessis 1eae2f5599 Add react-navigation 4 example 4 年之前
  Janic Duplessis e25bf577b5
Update .eslintrc.js 4 年之前
  Janic Duplessis 908744fa14
Update README.md 4 年之前
  Janic Duplessis 1b8c4d1ed8 1.0.0 4 年之前
  Janic Duplessis 8627e747b2 1.0.0-beta.3 4 年之前
  Janic Duplessis 7edb171db1 Fix prettier 4 年之前
  Juan David Nicholls Cardona 79ab4dd028
Add withSafeAreaConsumer HOC (#57) 4 年之前
  Janic Duplessis 05bdb89f95 Make example app easier to run 4 年之前
  luancurti 2e542e71c9
refactor(podfile): remove unnecessary use_native_modules! (#70) 4 年之前
  Janic Duplessis 24018ffa38 1.0.0-beta.2 4 年之前
  Janic Duplessis 9c2ab9c78a Fix tests 4 年之前
  Janic Duplessis 12da572a91 Use getWindowVisibleDisplayFrame to calculate edge insets on api < 20 4 年之前
  Janic Duplessis dad9cc41a6 Better backwards compat 4 年之前
  Janic Duplessis 3a25f1610b Properly disable flipper in iOS example ap 4 年之前
  Janic Duplessis 7620e8046d 1.0.0-beta.1 4 年之前
  Janic Duplessis 98ddd6c65e Fix crash in SafeAreaUtils.getFrame when view parent is null 4 年之前
  Janic Duplessis 960e7e5c6a Disable flipper in ios example app 4 年之前
  Janic Duplessis fdb7c0accf Bring back SafeAreaConsumer with deprecation warning 4 年之前
  Janic Duplessis e2101c6e37 Remove unused WindowChangeEvent, remove log 4 年之前
  Janic Duplessis 7a0b44107e 1.0.0-beta.0 4 年之前
  Janic Duplessis 4515714f01 1.0.0-0 4 年之前
  Janic Duplessis 6c9d3bde46 v2 4 年之前
  Janic Duplessis 436f19b495 Update deps and RN 4 年之前
  dependabot[bot] 1e60db778e
Bump acorn from 6.4.0 to 6.4.1 (#62) 4 年之前
共有 68 個文件被更改,包括 11156 次插入2919 次删除
  1. 0
    9
      .eslintrc.js
  2. 4
    0
      .gitignore
  3. 9
    9
      README.md
  4. 6
    6
      android/src/main/java/com/th3rdwave/safeareacontext/EdgeInsets.java
  5. 6
    4
      android/src/main/java/com/th3rdwave/safeareacontext/InsetsChangeEvent.java
  6. 22
    0
      android/src/main/java/com/th3rdwave/safeareacontext/Rect.java
  7. 39
    56
      android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaUtils.java
  8. 15
    14
      android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaView.java
  9. 15
    12
      android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaViewManager.java
  10. 52
    0
      android/src/main/java/com/th3rdwave/safeareacontext/SerializationUtils.java
  11. 10
    0
      babel.config.js
  12. 0
    56
      example/App.tsx
  13. 23
    3
      example/android/app/build.gradle
  14. 67
    0
      example/android/app/src/debug/java/com/safeareaviewexample/ReactNativeFlipper.java
  15. 2
    1
      example/android/app/src/main/AndroidManifest.xml
  16. 36
    0
      example/android/app/src/main/java/com/safeareaviewexample/MainActivity.java
  17. 43
    0
      example/android/app/src/main/java/com/safeareaviewexample/MainApplication.java
  18. 7
    0
      example/android/app/src/main/res/values-v28/styles.xml
  19. 5
    6
      example/android/build.gradle
  20. 6
    0
      example/android/gradle.properties
  21. 1
    1
      example/android/gradle/wrapper/gradle-wrapper.properties
  22. 15
    20
      example/android/gradlew
  23. 4
    1
      example/android/gradlew.bat
  24. 9
    0
      example/android/settings.gradle
  25. 1
    1
      example/app.json
  26. 5
    0
      example/index.expo.js
  27. 1
    1
      example/index.js
  28. 15
    32
      example/ios/Podfile
  29. 251
    190
      example/ios/Podfile.lock
  30. 4
    0
      example/ios/SafeAreaViewExample-Bridging-Header.h
  31. 0
    53
      example/ios/SafeAreaViewExample-tvOS/Info.plist
  32. 0
    24
      example/ios/SafeAreaViewExample-tvOSTests/Info.plist
  33. 47
    2
      example/ios/SafeAreaViewExample.xcodeproj/project.pbxproj
  34. 11
    15
      example/ios/SafeAreaViewExample.xcodeproj/xcshareddata/xcschemes/SafeAreaViewExample.xcscheme
  35. 0
    7
      example/ios/SafeAreaViewExample/AppDelegate.h
  36. 22
    7
      example/ios/SafeAreaViewExample/AppDelegate.m
  37. 9
    0
      example/ios/SafeAreaViewExample/File.swift
  38. 0
    7
      example/ios/SafeAreaViewExample/main.m
  39. 22
    0
      example/package.json
  40. 83
    0
      example/src/App.tsx
  41. 74
    0
      example/src/NativeStackExample.tsx
  42. 14
    0
      example/src/ReactNativeSafeAreaView.tsx
  43. 76
    0
      example/src/ReactNavigation4Example.tsx
  44. 76
    0
      example/src/ReactNavigation5Example.tsx
  45. 92
    0
      example/src/SimpleExample.tsx
  46. 15
    2
      ios/SafeAreaView/RNCSafeAreaView.m
  47. 13
    5
      ios/SafeAreaView/RNCSafeAreaViewManager.m
  48. 0
    17
      metro.config.js
  49. 39
    21
      package.json
  50. 17
    0
      src/InitialWindow.native.ts
  51. 8
    0
      src/InitialWindow.ts
  52. 0
    12
      src/InitialWindowSafeAreaInsets.ts
  53. 0
    4
      src/InitialWindowSafeAreaInsets.web.ts
  54. 6
    0
      src/NativeSafeAreaView.native.tsx
  55. 128
    2
      src/NativeSafeAreaView.tsx
  56. 0
    122
      src/NativeSafeAreaView.web.tsx
  57. 20
    2
      src/SafeArea.types.ts
  58. 123
    0
      src/SafeAreaContext.tsx
  59. 25
    0
      src/SafeAreaView.tsx
  60. 121
    0
      src/__tests__/SafeAreaContext-test.tsx
  61. 35
    0
      src/__tests__/SafeAreaView-test.tsx
  62. 32
    72
      src/__tests__/__snapshots__/SafeAreaContext-test.tsx.snap
  63. 57
    0
      src/__tests__/__snapshots__/SafeAreaView-test.tsx.snap
  64. 0
    169
      src/__tests__/index-test.tsx
  65. 41
    0
      src/__tests__/initialWindowMetrics-test.tsx
  66. 4
    80
      src/index.tsx
  67. 5
    1
      tsconfig.json
  68. 9268
    1873
      yarn.lock

+ 0
- 9
.eslintrc.js 查看文件

@@ -1,12 +1,3 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- */
9
-
10 1
 const typescriptEslintRecommended = require('@typescript-eslint/eslint-plugin/dist/configs/recommended.json');
11 2
 const typescriptEslintPrettier = require('eslint-config-prettier/@typescript-eslint');
12 3
 

+ 4
- 0
.gitignore 查看文件

@@ -60,3 +60,7 @@ index.ios.bundle
60 60
 
61 61
 # generated by bob
62 62
 lib/
63
+
64
+# Expo
65
+web-build
66
+.expo

+ 9
- 9
README.md 查看文件

@@ -96,10 +96,10 @@ function App() {
96 96
 Usage with hooks api:
97 97
 
98 98
 ```js
99
-import { useSafeArea } from 'react-native-safe-area-context';
99
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
100 100
 
101 101
 function HookComponent() {
102
-  const insets = useSafeArea();
102
+  const insets = useSafeAreaInsets();
103 103
 
104 104
   return <View style={{ paddingTop: insets.top }} />;
105 105
 }
@@ -108,14 +108,14 @@ function HookComponent() {
108 108
 Usage with consumer api:
109 109
 
110 110
 ```js
111
-import { SafeAreaConsumer } from 'react-native-safe-area-context';
111
+import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
112 112
 
113 113
 class ClassComponent extends React.Component {
114 114
   render() {
115 115
     return (
116
-      <SafeAreaConsumer>
116
+      <SafeAreaInsetsContext.Consumer>
117 117
         {insets => <View style={{ paddingTop: insets.top }} />}
118
-      </SafeAreaConsumer>
118
+      </SafeAreaInsetsContext.Consumer>
119 119
     );
120 120
   }
121 121
 }
@@ -137,21 +137,21 @@ function SomeComponent() {
137 137
 
138 138
 ### Web SSR
139 139
 
140
-If you are doing server side rendering on the web you can use `initialSafeAreaInsets` to inject insets value based on the device the user has, or simply pass zero values. Since insets measurement is async it will break rendering your page content otherwise.
140
+If you are doing server side rendering on the web you can use `initialMetrics` to inject insets and frame value based on the device the user has, or simply pass zero values. Since insets measurement is async it will break rendering your page content otherwise.
141 141
 
142 142
 ### Optimization
143 143
 
144
-To speed up the initial render, you can import `initialWindowSafeAreaInsets` from this package and set as the `initialSafeAreaInsets` prop on the provider as described in Web SSR. You cannot do this if your provider remounts, or you are using `react-native-navigation`.
144
+To speed up the initial render, you can import `initialWindowMetrics` from this package and set as the `initialMetrics` prop on the provider as described in Web SSR. You cannot do this if your provider remounts, or you are using `react-native-navigation`.
145 145
 
146 146
 ```js
147 147
 import {
148 148
   SafeAreaProvider,
149
-  initialWindowSafeAreaInsets
149
+  initialWindowMetrics
150 150
 } from 'react-native-safe-area-context';
151 151
 
152 152
 function App() {
153 153
   return (
154
-    <SafeAreaProvider initialSafeAreaInsets={initialWindowSafeAreaInsets}>
154
+    <SafeAreaProvider initialMetrics={initialWindowMetrics}>
155 155
       ...
156 156
     </SafeAreaProvider>
157 157
   );

+ 6
- 6
android/src/main/java/com/th3rdwave/safeareacontext/EdgeInsets.java 查看文件

@@ -1,19 +1,19 @@
1 1
 package com.th3rdwave.safeareacontext;
2 2
 
3 3
 /* package */ class EdgeInsets {
4
-  public float top;
5
-  public float right;
6
-  public float bottom;
7
-  public float left;
4
+  float top;
5
+  float right;
6
+  float bottom;
7
+  float left;
8 8
 
9
-  public EdgeInsets(float top, float right, float bottom, float left) {
9
+  EdgeInsets(float top, float right, float bottom, float left) {
10 10
     this.top = top;
11 11
     this.right = right;
12 12
     this.bottom = bottom;
13 13
     this.left = left;
14 14
   }
15 15
 
16
-  public boolean equalsToEdgeInsets(EdgeInsets other) {
16
+  boolean equalsToEdgeInsets(EdgeInsets other) {
17 17
     if (this == other) {
18 18
       return true;
19 19
     }

+ 6
- 4
android/src/main/java/com/th3rdwave/safeareacontext/InsetsChangeEvent.java 查看文件

@@ -2,19 +2,20 @@ package com.th3rdwave.safeareacontext;
2 2
 
3 3
 import com.facebook.react.bridge.Arguments;
4 4
 import com.facebook.react.bridge.WritableMap;
5
-import com.facebook.react.uimanager.PixelUtil;
6 5
 import com.facebook.react.uimanager.events.Event;
7 6
 import com.facebook.react.uimanager.events.RCTEventEmitter;
8 7
 
9 8
 /* package */  class InsetsChangeEvent extends Event<InsetsChangeEvent> {
10
-  public static final String EVENT_NAME = "topInsetsChange";
9
+  static final String EVENT_NAME = "topInsetsChange";
11 10
 
12 11
   private EdgeInsets mInsets;
12
+  private Rect mFrame;
13 13
 
14
-  protected InsetsChangeEvent(int viewTag, EdgeInsets insets) {
14
+  InsetsChangeEvent(int viewTag, EdgeInsets insets, Rect frame) {
15 15
     super(viewTag);
16 16
 
17 17
     mInsets = insets;
18
+    mFrame = frame;
18 19
   }
19 20
 
20 21
   @Override
@@ -25,7 +26,8 @@ import com.facebook.react.uimanager.events.RCTEventEmitter;
25 26
   @Override
26 27
   public void dispatch(RCTEventEmitter rctEventEmitter) {
27 28
     WritableMap event = Arguments.createMap();
28
-    event.putMap("insets", SafeAreaUtils.edgeInsetsToJsMap(mInsets));
29
+    event.putMap("insets", SerializationUtils.edgeInsetsToJsMap(mInsets));
30
+    event.putMap("frame", SerializationUtils.rectToJsMap(mFrame));
29 31
     rctEventEmitter.receiveEvent(getViewTag(), getEventName(), event);
30 32
   }
31 33
 }

+ 22
- 0
android/src/main/java/com/th3rdwave/safeareacontext/Rect.java 查看文件

@@ -0,0 +1,22 @@
1
+package com.th3rdwave.safeareacontext;
2
+
3
+/* package */ class Rect {
4
+  float x;
5
+  float y;
6
+  float width;
7
+  float height;
8
+
9
+  Rect(float x, float y, float width, float height) {
10
+    this.x = x;
11
+    this.y = y;
12
+    this.width = width;
13
+    this.height = height;
14
+  }
15
+
16
+  boolean equalsToRect(Rect other) {
17
+    if (this == other) {
18
+      return true;
19
+    }
20
+    return this.x == other.x && this.y == other.y && this.width == other.width && this.height == other.height;
21
+  }
22
+}

+ 39
- 56
android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaUtils.java 查看文件

@@ -2,88 +2,71 @@ package com.th3rdwave.safeareacontext;
2 2
 
3 3
 import android.graphics.Rect;
4 4
 import android.os.Build;
5
-import android.view.Surface;
6 5
 import android.view.View;
6
+import android.view.ViewGroup;
7 7
 import android.view.WindowInsets;
8
-import android.view.WindowManager;
9
-
10
-import com.facebook.react.bridge.Arguments;
11
-import com.facebook.react.bridge.WritableMap;
12
-import com.facebook.react.common.MapBuilder;
13
-import com.facebook.react.uimanager.PixelUtil;
14
-
15
-import java.util.Map;
16 8
 
17 9
 import android.support.annotation.Nullable;
18 10
 
19 11
 /* package */ class SafeAreaUtils {
20
-  static WritableMap edgeInsetsToJsMap(EdgeInsets insets) {
21
-    WritableMap insetsMap = Arguments.createMap();
22
-    insetsMap.putDouble("top", PixelUtil.toDIPFromPixel(insets.top));
23
-    insetsMap.putDouble("right", PixelUtil.toDIPFromPixel(insets.right));
24
-    insetsMap.putDouble("bottom", PixelUtil.toDIPFromPixel(insets.bottom));
25
-    insetsMap.putDouble("left", PixelUtil.toDIPFromPixel(insets.left));
26
-    return insetsMap;
27
-  }
28 12
 
29
-  static Map<String, Float> edgeInsetsToJavaMap(EdgeInsets insets) {
30
-    return MapBuilder.of(
31
-        "top",
32
-        PixelUtil.toDIPFromPixel(insets.top),
33
-        "right",
34
-        PixelUtil.toDIPFromPixel(insets.right),
35
-        "bottom",
36
-        PixelUtil.toDIPFromPixel(insets.bottom),
37
-        "left",
38
-        PixelUtil.toDIPFromPixel(insets.left));
39
-  }
40
-
41
-  static @Nullable EdgeInsets getSafeAreaInsets(WindowManager windowManager, View rootView) {
42
-    // Window insets are parts of the window that are covered by system views (status bar,
43
-    // navigation bar, notches). There are no apis the get these values for android < M so we
44
-    // do a best effort polyfill.
45
-    EdgeInsets windowInsets;
13
+  private static @Nullable EdgeInsets getRootWindowInsetsCompat(View rootView) {
46 14
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
47 15
       WindowInsets insets = rootView.getRootWindowInsets();
48 16
       if (insets == null) {
49 17
         return null;
50 18
       }
51
-      windowInsets = new EdgeInsets(
19
+      return new EdgeInsets(
52 20
           insets.getSystemWindowInsetTop(),
53 21
           insets.getSystemWindowInsetRight(),
54 22
           insets.getSystemWindowInsetBottom(),
55 23
           insets.getSystemWindowInsetLeft());
56 24
     } else {
57
-      int rotation = windowManager.getDefaultDisplay().getRotation();
58
-      int statusBarHeight = 0;
59
-      int resourceId = rootView.getResources().getIdentifier("status_bar_height", "dimen", "android");
60
-      if (resourceId > 0) {
61
-        statusBarHeight = rootView.getResources().getDimensionPixelSize(resourceId);
62
-      }
63
-      int navbarHeight = 0;
64
-      resourceId = rootView.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
65
-      if (resourceId > 0) {
66
-        navbarHeight = rootView.getResources().getDimensionPixelSize(resourceId);
67
-      }
25
+      Rect visibleRect = new Rect();
26
+      rootView.getWindowVisibleDisplayFrame(visibleRect);
27
+      return new EdgeInsets(
28
+          visibleRect.top,
29
+          rootView.getWidth() - visibleRect.right,
30
+          rootView.getHeight() - visibleRect.bottom,
31
+          visibleRect.left);
32
+    }
33
+  }
68 34
 
69
-      windowInsets = new EdgeInsets(
70
-          statusBarHeight,
71
-          rotation == Surface.ROTATION_90 ? navbarHeight : 0,
72
-          rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ? navbarHeight : 0,
73
-          rotation == Surface.ROTATION_270 ? navbarHeight : 0);
35
+  static @Nullable EdgeInsets getSafeAreaInsets(View rootView, View view) {
36
+    EdgeInsets windowInsets = getRootWindowInsetsCompat(rootView);
37
+    if (windowInsets == null) {
38
+      return null;
74 39
     }
75 40
 
76
-    // Calculate the part of the root view that overlaps with window insets.
77
-    View contentView = rootView.findViewById(android.R.id.content);
41
+    // Calculate the part of the view that overlaps with window insets.
78 42
     float windowWidth = rootView.getWidth();
79 43
     float windowHeight = rootView.getHeight();
80 44
     Rect visibleRect = new Rect();
81
-    contentView.getGlobalVisibleRect(visibleRect);
45
+    view.getGlobalVisibleRect(visibleRect);
82 46
 
83 47
     windowInsets.top = Math.max(windowInsets.top - visibleRect.top, 0);
84 48
     windowInsets.left = Math.max(windowInsets.left - visibleRect.left, 0);
85
-    windowInsets.bottom = Math.max(visibleRect.top + contentView.getHeight() + windowInsets.bottom - windowHeight, 0);
86
-    windowInsets.right = Math.max(visibleRect.left + contentView.getWidth() + windowInsets.right - windowWidth, 0);
49
+    windowInsets.bottom = Math.max(visibleRect.top + view.getHeight() + windowInsets.bottom - windowHeight, 0);
50
+    windowInsets.right = Math.max(visibleRect.left + view.getWidth() + windowInsets.right - windowWidth, 0);
87 51
     return windowInsets;
88 52
   }
53
+
54
+  static @Nullable com.th3rdwave.safeareacontext.Rect getFrame(ViewGroup rootView, View view) {
55
+    // This can happen while the view gets unmounted.
56
+    if (view.getParent() == null) {
57
+      return null;
58
+    }
59
+    Rect offset = new Rect();
60
+    view.getDrawingRect(offset);
61
+    try {
62
+      rootView.offsetDescendantRectToMyCoords(view, offset);
63
+    } catch (IllegalArgumentException ex) {
64
+      // This can throw if the view is not a descendant of rootView. This should not
65
+      // happen but avoid potential crashes.
66
+      ex.printStackTrace();
67
+      return null;
68
+    }
69
+
70
+    return new com.th3rdwave.safeareacontext.Rect(offset.left, offset.top, view.getWidth(), view.getHeight());
71
+  }
89 72
 }

+ 15
- 14
android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaView.java 查看文件

@@ -1,39 +1,40 @@
1 1
 package com.th3rdwave.safeareacontext;
2 2
 
3
+import android.annotation.SuppressLint;
3 4
 import android.content.Context;
4
-import android.graphics.Rect;
5
-import android.os.Build;
6
-import android.view.Surface;
7
-import android.view.View;
5
+import android.view.ViewGroup;
8 6
 import android.view.ViewTreeObserver;
9
-import android.view.WindowInsets;
10
-import android.view.WindowManager;
11 7
 
12 8
 import com.facebook.infer.annotation.Assertions;
13 9
 import com.facebook.react.views.view.ReactViewGroup;
14 10
 
15 11
 import android.support.annotation.Nullable;
16 12
 
13
+@SuppressLint("ViewConstructor")
17 14
 public class SafeAreaView extends ReactViewGroup implements ViewTreeObserver.OnGlobalLayoutListener {
18 15
   public interface OnInsetsChangeListener {
19
-    void onInsetsChange(SafeAreaView view, EdgeInsets insets);
16
+    void onInsetsChange(SafeAreaView view, EdgeInsets insets, Rect frame);
20 17
   }
21 18
 
22 19
   private @Nullable OnInsetsChangeListener mInsetsChangeListener;
23
-  private final WindowManager mWindowManager;
24 20
   private @Nullable EdgeInsets mLastInsets;
21
+  private @Nullable Rect mLastFrame;
25 22
 
26
-  public SafeAreaView(Context context, WindowManager windowManager) {
23
+  public SafeAreaView(Context context) {
27 24
     super(context);
28
-
29
-    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
30 25
   }
31 26
 
32 27
   private void maybeUpdateInsets() {
33
-    EdgeInsets edgeInsets = SafeAreaUtils.getSafeAreaInsets(mWindowManager, getRootView());
34
-    if (edgeInsets != null && (mLastInsets == null || !mLastInsets.equalsToEdgeInsets(edgeInsets))) {
35
-      Assertions.assertNotNull(mInsetsChangeListener).onInsetsChange(this, edgeInsets);
28
+    EdgeInsets edgeInsets = SafeAreaUtils.getSafeAreaInsets(getRootView(), this);
29
+    Rect frame = SafeAreaUtils.getFrame((ViewGroup) getRootView(), this);
30
+    if (edgeInsets != null && frame != null &&
31
+        (mLastInsets == null ||
32
+            mLastFrame == null ||
33
+            !mLastInsets.equalsToEdgeInsets(edgeInsets) ||
34
+            !mLastFrame.equalsToRect(frame))) {
35
+      Assertions.assertNotNull(mInsetsChangeListener).onInsetsChange(this, edgeInsets, frame);
36 36
       mLastInsets = edgeInsets;
37
+      mLastFrame = frame;
37 38
     }
38 39
   }
39 40
 

+ 15
- 12
android/src/main/java/com/th3rdwave/safeareacontext/SafeAreaViewManager.java 查看文件

@@ -1,9 +1,8 @@
1 1
 package com.th3rdwave.safeareacontext;
2 2
 
3 3
 import android.app.Activity;
4
-import android.content.Context;
5 4
 import android.view.View;
6
-import android.view.WindowManager;
5
+import android.view.ViewGroup;
7 6
 
8 7
 import com.facebook.react.bridge.ReactApplicationContext;
9 8
 import com.facebook.react.common.MapBuilder;
@@ -19,13 +18,11 @@ import android.support.annotation.Nullable;
19 18
 
20 19
 public class SafeAreaViewManager extends ViewGroupManager<SafeAreaView> {
21 20
   private final ReactApplicationContext mContext;
22
-  private final WindowManager mWindowManager;
23 21
 
24 22
   public SafeAreaViewManager(ReactApplicationContext context) {
25 23
     super();
26 24
 
27 25
     mContext = context;
28
-    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
29 26
   }
30 27
 
31 28
   @Override
@@ -37,7 +34,7 @@ public class SafeAreaViewManager extends ViewGroupManager<SafeAreaView> {
37 34
   @Override
38 35
   @NonNull
39 36
   public SafeAreaView createViewInstance(@NonNull ThemedReactContext context) {
40
-    return new SafeAreaView(context, mWindowManager);
37
+    return new SafeAreaView(context);
41 38
   }
42 39
 
43 40
   @Override
@@ -46,8 +43,8 @@ public class SafeAreaViewManager extends ViewGroupManager<SafeAreaView> {
46 43
         reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
47 44
     view.setOnInsetsChangeListener(new SafeAreaView.OnInsetsChangeListener() {
48 45
       @Override
49
-      public void onInsetsChange(SafeAreaView view, EdgeInsets insets) {
50
-        dispatcher.dispatchEvent(new InsetsChangeEvent(view.getId(), insets));
46
+      public void onInsetsChange(SafeAreaView view, EdgeInsets insets, Rect frame) {
47
+        dispatcher.dispatchEvent(new InsetsChangeEvent(view.getId(), insets, frame));
51 48
       }
52 49
     });
53 50
   }
@@ -67,18 +64,24 @@ public class SafeAreaViewManager extends ViewGroupManager<SafeAreaView> {
67 64
       return null;
68 65
     }
69 66
 
70
-    View decorView = activity.getWindow().getDecorView();
67
+    ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
71 68
     if (decorView == null) {
72 69
       return null;
73 70
     }
74 71
 
75
-    EdgeInsets insets = SafeAreaUtils.getSafeAreaInsets(mWindowManager, decorView);
76
-    if (insets == null) {
72
+    View contentView = decorView.findViewById(android.R.id.content);
73
+    EdgeInsets insets = SafeAreaUtils.getSafeAreaInsets(decorView, contentView);
74
+    Rect frame = SafeAreaUtils.getFrame(decorView, contentView);
75
+    if (insets == null || frame == null) {
77 76
       return null;
78 77
     }
79 78
     return MapBuilder.<String, Object>of(
80
-        "initialWindowSafeAreaInsets",
81
-        SafeAreaUtils.edgeInsetsToJavaMap(insets));
79
+        "initialWindowMetrics",
80
+        MapBuilder.<String, Object>of(
81
+            "insets",
82
+            SerializationUtils.edgeInsetsToJavaMap(insets),
83
+            "frame",
84
+            SerializationUtils.rectToJavaMap(frame)));
82 85
 
83 86
   }
84 87
 }

+ 52
- 0
android/src/main/java/com/th3rdwave/safeareacontext/SerializationUtils.java 查看文件

@@ -0,0 +1,52 @@
1
+package com.th3rdwave.safeareacontext;
2
+
3
+import com.facebook.react.bridge.Arguments;
4
+import com.facebook.react.bridge.WritableMap;
5
+import com.facebook.react.common.MapBuilder;
6
+import com.facebook.react.uimanager.PixelUtil;
7
+
8
+import java.util.Map;
9
+
10
+/* package */ class SerializationUtils {
11
+  static WritableMap edgeInsetsToJsMap(EdgeInsets insets) {
12
+    WritableMap insetsMap = Arguments.createMap();
13
+    insetsMap.putDouble("top", PixelUtil.toDIPFromPixel(insets.top));
14
+    insetsMap.putDouble("right", PixelUtil.toDIPFromPixel(insets.right));
15
+    insetsMap.putDouble("bottom", PixelUtil.toDIPFromPixel(insets.bottom));
16
+    insetsMap.putDouble("left", PixelUtil.toDIPFromPixel(insets.left));
17
+    return insetsMap;
18
+  }
19
+
20
+  static Map<String, Float> edgeInsetsToJavaMap(EdgeInsets insets) {
21
+    return MapBuilder.of(
22
+        "top",
23
+        PixelUtil.toDIPFromPixel(insets.top),
24
+        "right",
25
+        PixelUtil.toDIPFromPixel(insets.right),
26
+        "bottom",
27
+        PixelUtil.toDIPFromPixel(insets.bottom),
28
+        "left",
29
+        PixelUtil.toDIPFromPixel(insets.left));
30
+  }
31
+
32
+  static WritableMap rectToJsMap(Rect rect) {
33
+    WritableMap rectMap = Arguments.createMap();
34
+    rectMap.putDouble("x", PixelUtil.toDIPFromPixel(rect.x));
35
+    rectMap.putDouble("y", PixelUtil.toDIPFromPixel(rect.y));
36
+    rectMap.putDouble("width", PixelUtil.toDIPFromPixel(rect.width));
37
+    rectMap.putDouble("height", PixelUtil.toDIPFromPixel(rect.height));
38
+    return rectMap;
39
+  }
40
+
41
+  static Map<String, Float> rectToJavaMap(Rect rect) {
42
+    return MapBuilder.of(
43
+        "x",
44
+        PixelUtil.toDIPFromPixel(rect.x),
45
+        "y",
46
+        PixelUtil.toDIPFromPixel(rect.y),
47
+        "width",
48
+        PixelUtil.toDIPFromPixel(rect.width),
49
+        "height",
50
+        PixelUtil.toDIPFromPixel(rect.height));
51
+  }
52
+}

+ 10
- 0
babel.config.js 查看文件

@@ -1,3 +1,13 @@
1 1
 module.exports = {
2 2
   presets: ['module:metro-react-native-babel-preset'],
3
+  plugins: [
4
+    [
5
+      'module-resolver',
6
+      {
7
+        alias: {
8
+          'react-native-safe-area-context': './src',
9
+        },
10
+      },
11
+    ],
12
+  ],
3 13
 };

+ 0
- 56
example/App.tsx 查看文件

@@ -1,56 +0,0 @@
1
-import * as React from 'react';
2
-import { View, Text, StatusBar } from 'react-native';
3
-
4
-// import { SafeAreaProvider, useSafeArea } from 'react-native-safe-area-context'; in your app.
5
-import {
6
-  SafeAreaProvider,
7
-  useSafeArea,
8
-  initialWindowSafeAreaInsets,
9
-} from '../src';
10
-
11
-const Screen = () => {
12
-  const insets = useSafeArea();
13
-
14
-  return (
15
-    <>
16
-      <StatusBar
17
-        barStyle="dark-content"
18
-        translucent
19
-        backgroundColor="transparent"
20
-      />
21
-      <View
22
-        style={{
23
-          flex: 1,
24
-          backgroundColor: 'red',
25
-          paddingTop: insets.top,
26
-          paddingLeft: insets.left,
27
-          paddingBottom: insets.bottom,
28
-          paddingRight: insets.right,
29
-        }}
30
-      >
31
-        <View
32
-          style={{
33
-            flex: 1,
34
-            backgroundColor: 'white',
35
-            alignItems: 'center',
36
-            justifyContent: 'center',
37
-          }}
38
-        >
39
-          <Text>Insets: {JSON.stringify(insets, null, 2)}</Text>
40
-          <Text>
41
-            Initial insets:{' '}
42
-            {JSON.stringify(initialWindowSafeAreaInsets, null, 2)}
43
-          </Text>
44
-        </View>
45
-      </View>
46
-    </>
47
-  );
48
-};
49
-
50
-export default function App() {
51
-  return (
52
-    <SafeAreaProvider>
53
-      <Screen />
54
-    </SafeAreaProvider>
55
-  );
56
-}

+ 23
- 3
example/android/app/build.gradle 查看文件

@@ -15,10 +15,12 @@ import com.android.build.OutputFile
15 15
  *   // the name of the generated asset file containing your JS bundle
16 16
  *   bundleAssetName: "index.android.bundle",
17 17
  *
18
- *   // the entry file for bundle generation
18
+ *   // the entry file for bundle generation. If none specified and
19
+ *   // "index.android.js" exists, it will be used. Otherwise "index.js" is
20
+ *   // default. Can be overridden with ENTRY_FILE environment variable.
19 21
  *   entryFile: "index.android.js",
20 22
  *
21
- *   // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format
23
+ *   // https://reactnative.dev/docs/performance#enable-the-ram-format
22 24
  *   bundleCommand: "ram-bundle",
23 25
  *
24 26
  *   // whether to bundle JS and assets in debug mode
@@ -148,12 +150,13 @@ android {
148 150
         }
149 151
         release {
150 152
             // Caution! In production, you need to generate your own keystore file.
151
-            // see https://facebook.github.io/react-native/docs/signed-apk-android.
153
+            // see https://reactnative.dev/docs/signed-apk-android.
152 154
             signingConfig signingConfigs.debug
153 155
             minifyEnabled enableProguardInReleaseBuilds
154 156
             proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
155 157
         }
156 158
     }
159
+
157 160
     // applicationVariants are e.g. debug, release
158 161
     applicationVariants.all { variant ->
159 162
         variant.outputs.each { output ->
@@ -181,8 +184,20 @@ android {
181 184
 
182 185
 dependencies {
183 186
     implementation fileTree(dir: "libs", include: ["*.jar"])
187
+    //noinspection GradleDynamicVersion
184 188
     implementation "com.facebook.react:react-native:+"  // From node_modules
185 189
 
190
+    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
191
+    debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
192
+      exclude group:'com.facebook.fbjni'
193
+    }
194
+    debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
195
+        exclude group:'com.facebook.flipper'
196
+    }
197
+    debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
198
+        exclude group:'com.facebook.flipper'
199
+    }
200
+
186 201
     if (enableHermes) {
187 202
       def hermesPath = "../../../node_modules/hermesvm/android/";
188 203
       debugImplementation files(hermesPath + "hermes-debug.aar")
@@ -191,6 +206,11 @@ dependencies {
191 206
       implementation jscFlavor
192 207
     }
193 208
 
209
+    implementation project(":react-native-community-async-storage")
210
+    implementation project(":react-native-gesture-handler")
211
+    implementation project(":react-native-reanimated")
212
+    implementation project(":react-native-screens")
213
+
194 214
     implementation project(":react-native-safe-area-context")
195 215
 }
196 216
 

+ 67
- 0
example/android/app/src/debug/java/com/safeareaviewexample/ReactNativeFlipper.java 查看文件

@@ -0,0 +1,67 @@
1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * <p>This source code is licensed under the MIT license found in the LICENSE file in the root
5
+ * directory of this source tree.
6
+ */
7
+package com.safeareaviewexample;
8
+import android.content.Context;
9
+import com.facebook.flipper.android.AndroidFlipperClient;
10
+import com.facebook.flipper.android.utils.FlipperUtils;
11
+import com.facebook.flipper.core.FlipperClient;
12
+import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
13
+import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
14
+import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
15
+import com.facebook.flipper.plugins.inspector.DescriptorMapping;
16
+import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
17
+import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
18
+import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
19
+import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
20
+import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
21
+import com.facebook.react.ReactInstanceManager;
22
+import com.facebook.react.bridge.ReactContext;
23
+import com.facebook.react.modules.network.NetworkingModule;
24
+import okhttp3.OkHttpClient;
25
+public class ReactNativeFlipper {
26
+  public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
27
+    if (FlipperUtils.shouldEnableFlipper(context)) {
28
+      final FlipperClient client = AndroidFlipperClient.getInstance(context);
29
+      client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
30
+      client.addPlugin(new ReactFlipperPlugin());
31
+      client.addPlugin(new DatabasesFlipperPlugin(context));
32
+      client.addPlugin(new SharedPreferencesFlipperPlugin(context));
33
+      client.addPlugin(CrashReporterPlugin.getInstance());
34
+      NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
35
+      NetworkingModule.setCustomClientBuilder(
36
+          new NetworkingModule.CustomClientBuilder() {
37
+            @Override
38
+            public void apply(OkHttpClient.Builder builder) {
39
+              builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
40
+            }
41
+          });
42
+      client.addPlugin(networkFlipperPlugin);
43
+      client.start();
44
+      // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
45
+      // Hence we run if after all native modules have been initialized
46
+      ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
47
+      if (reactContext == null) {
48
+        reactInstanceManager.addReactInstanceEventListener(
49
+            new ReactInstanceManager.ReactInstanceEventListener() {
50
+              @Override
51
+              public void onReactContextInitialized(ReactContext reactContext) {
52
+                reactInstanceManager.removeReactInstanceEventListener(this);
53
+                reactContext.runOnNativeModulesQueueThread(
54
+                    new Runnable() {
55
+                      @Override
56
+                      public void run() {
57
+                        client.addPlugin(new FrescoFlipperPlugin());
58
+                      }
59
+                    });
60
+              }
61
+            });
62
+      } else {
63
+        client.addPlugin(new FrescoFlipperPlugin());
64
+      }
65
+    }
66
+  }
67
+}

+ 2
- 1
example/android/app/src/main/AndroidManifest.xml 查看文件

@@ -13,7 +13,8 @@
13 13
       <activity
14 14
         android:name=".MainActivity"
15 15
         android:label="@string/app_name"
16
-        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
16
+        android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
17
+        android:launchMode="singleTask"
17 18
         android:windowSoftInputMode="adjustResize">
18 19
         <intent-filter>
19 20
             <action android:name="android.intent.action.MAIN" />

+ 36
- 0
example/android/app/src/main/java/com/safeareaviewexample/MainActivity.java 查看文件

@@ -1,9 +1,19 @@
1 1
 package com.safeareaviewexample;
2 2
 
3
+import android.os.Bundle;
4
+import android.view.View;
5
+import android.view.WindowManager;
6
+
3 7
 import com.facebook.react.ReactActivity;
8
+import com.facebook.react.ReactActivityDelegate;
9
+import com.facebook.react.ReactRootView;
10
+import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
4 11
 
5 12
 public class MainActivity extends ReactActivity {
6 13
 
14
+    private static final boolean TEST_TRANSLUCENT_STATUS_BAR = true;
15
+    private static final boolean TEST_TRANSLUCENT_NAVBAR = true;
16
+
7 17
     /**
8 18
      * Returns the name of the main component registered from JavaScript.
9 19
      * This is used to schedule rendering of the component.
@@ -12,4 +22,30 @@ public class MainActivity extends ReactActivity {
12 22
     protected String getMainComponentName() {
13 23
         return "SafeAreaViewExample";
14 24
     }
25
+
26
+    @Override
27
+    protected ReactActivityDelegate createReactActivityDelegate() {
28
+      return new ReactActivityDelegate(this, getMainComponentName()) {
29
+        @Override
30
+        protected ReactRootView createRootView() {
31
+          return new RNGestureHandlerEnabledRootView(MainActivity.this);
32
+        }
33
+      };
34
+    }
35
+
36
+    @Override
37
+    protected void onCreate(Bundle savedInstanceState) {
38
+        super.onCreate(savedInstanceState);
39
+
40
+        if (TEST_TRANSLUCENT_STATUS_BAR) {
41
+            getWindow().getDecorView().setSystemUiVisibility(
42
+                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
43
+        }
44
+        if (TEST_TRANSLUCENT_NAVBAR) {
45
+            getWindow().setFlags(
46
+                WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
47
+                WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
48
+        }
49
+
50
+    }
15 51
 }

+ 43
- 0
example/android/app/src/main/java/com/safeareaviewexample/MainApplication.java 查看文件

@@ -1,14 +1,21 @@
1 1
 package com.safeareaviewexample;
2 2
 
3 3
 import android.app.Application;
4
+import android.content.Context;
4 5
 
5 6
 import com.facebook.react.ReactApplication;
7
+import com.facebook.react.ReactInstanceManager;
6 8
 import com.facebook.react.ReactNativeHost;
7 9
 import com.facebook.react.ReactPackage;
8 10
 import com.facebook.react.shell.MainReactPackage;
9 11
 import com.facebook.soloader.SoLoader;
10 12
 import com.th3rdwave.safeareacontext.SafeAreaContextPackage;
13
+import com.swmansion.rnscreens.RNScreensPackage;
14
+import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
15
+import com.swmansion.reanimated.ReanimatedPackage;
16
+import com.reactnativecommunity.asyncstorage.AsyncStoragePackage;
11 17
 
18
+import java.lang.reflect.InvocationTargetException;
12 19
 import java.util.Arrays;
13 20
 import java.util.List;
14 21
 
@@ -24,6 +31,10 @@ public class MainApplication extends Application implements ReactApplication {
24 31
     protected List<ReactPackage> getPackages() {
25 32
       return Arrays.asList(
26 33
           new MainReactPackage(),
34
+          new RNScreensPackage(),
35
+          new RNGestureHandlerPackage(),
36
+          new ReanimatedPackage(),
37
+          new AsyncStoragePackage(),
27 38
           new SafeAreaContextPackage());
28 39
     }
29 40
 
@@ -42,5 +53,37 @@ public class MainApplication extends Application implements ReactApplication {
42 53
   public void onCreate() {
43 54
     super.onCreate();
44 55
     SoLoader.init(this, /* native exopackage */ false);
56
+    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
57
+  }
58
+
59
+  /**
60
+   * Loads Flipper in React Native templates. Call this in the onCreate method with something like
61
+   * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
62
+   *
63
+   * @param context
64
+   * @param reactInstanceManager
65
+   */
66
+  private static void initializeFlipper(
67
+      Context context, ReactInstanceManager reactInstanceManager) {
68
+    if (BuildConfig.DEBUG) {
69
+      try {
70
+        /*
71
+         We use reflection here to pick up the class that initializes Flipper,
72
+         since Flipper library is not available in release mode
73
+        */
74
+        Class<?> aClass = Class.forName("com.safeareaviewexample.ReactNativeFlipper");
75
+        aClass
76
+            .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
77
+            .invoke(null, context, reactInstanceManager);
78
+      } catch (ClassNotFoundException e) {
79
+        e.printStackTrace();
80
+      } catch (NoSuchMethodException e) {
81
+        e.printStackTrace();
82
+      } catch (IllegalAccessException e) {
83
+        e.printStackTrace();
84
+      } catch (InvocationTargetException e) {
85
+        e.printStackTrace();
86
+      }
87
+    }
45 88
   }
46 89
 }

+ 7
- 0
example/android/app/src/main/res/values-v28/styles.xml 查看文件

@@ -0,0 +1,7 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<resources>
3
+
4
+    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
5
+        <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
6
+    </style>
7
+</resources>

+ 5
- 6
example/android/build.gradle 查看文件

@@ -2,19 +2,17 @@
2 2
 
3 3
 buildscript {
4 4
     ext {
5
-        buildToolsVersion = "28.0.3"
5
+        buildToolsVersion = "29.0.2"
6 6
         minSdkVersion = 16
7
-        compileSdkVersion = 28
8
-        targetSdkVersion = 28
9
-        supportLibVersion = "28.0.0"
7
+        compileSdkVersion = 29
8
+        targetSdkVersion = 29
10 9
     }
11 10
     repositories {
12 11
         google()
13 12
         jcenter()
14 13
     }
15 14
     dependencies {
16
-        classpath("com.android.tools.build:gradle:3.4.1")
17
-
15
+        classpath("com.android.tools.build:gradle:3.5.3")
18 16
         // NOTE: Do not place your application dependencies here; they belong
19 17
         // in the individual module build.gradle files
20 18
     }
@@ -34,5 +32,6 @@ allprojects {
34 32
 
35 33
         google()
36 34
         jcenter()
35
+        maven { url 'https://www.jitpack.io' }
37 36
     }
38 37
 }

+ 6
- 0
example/android/gradle.properties 查看文件

@@ -17,5 +17,11 @@
17 17
 # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 18
 # org.gradle.parallel=true
19 19
 
20
+# AndroidX package structure to make it clearer which packages are bundled with the
21
+# Android operating system, and which are packaged with your app's APK
22
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
20 23
 android.useAndroidX=true
24
+# Automatically convert third-party libraries to use AndroidX
21 25
 android.enableJetifier=true
26
+# Version of flipper SDK to use with React Native
27
+FLIPPER_VERSION=0.33.1

+ 1
- 1
example/android/gradle/wrapper/gradle-wrapper.properties 查看文件

@@ -1,5 +1,5 @@
1 1
 distributionBase=GRADLE_USER_HOME
2 2
 distributionPath=wrapper/dists
3
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
3
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-all.zip
4 4
 zipStoreBase=GRADLE_USER_HOME
5 5
 zipStorePath=wrapper/dists

+ 15
- 20
example/android/gradlew 查看文件

@@ -7,7 +7,7 @@
7 7
 # you may not use this file except in compliance with the License.
8 8
 # You may obtain a copy of the License at
9 9
 #
10
-#      http://www.apache.org/licenses/LICENSE-2.0
10
+#      https://www.apache.org/licenses/LICENSE-2.0
11 11
 #
12 12
 # Unless required by applicable law or agreed to in writing, software
13 13
 # distributed under the License is distributed on an "AS IS" BASIS,
@@ -125,8 +125,8 @@ if $darwin; then
125 125
     GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
126 126
 fi
127 127
 
128
-# For Cygwin, switch paths to Windows format before running java
129
-if $cygwin ; then
128
+# For Cygwin or MSYS, switch paths to Windows format before running java
129
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
130 130
     APP_HOME=`cygpath --path --mixed "$APP_HOME"`
131 131
     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
132 132
     JAVACMD=`cygpath --unix "$JAVACMD"`
@@ -154,19 +154,19 @@ if $cygwin ; then
154 154
         else
155 155
             eval `echo args$i`="\"$arg\""
156 156
         fi
157
-        i=$((i+1))
157
+        i=`expr $i + 1`
158 158
     done
159 159
     case $i in
160
-        (0) set -- ;;
161
-        (1) set -- "$args0" ;;
162
-        (2) set -- "$args0" "$args1" ;;
163
-        (3) set -- "$args0" "$args1" "$args2" ;;
164
-        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
165
-        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
166
-        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
167
-        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
168
-        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
169
-        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
160
+        0) set -- ;;
161
+        1) set -- "$args0" ;;
162
+        2) set -- "$args0" "$args1" ;;
163
+        3) set -- "$args0" "$args1" "$args2" ;;
164
+        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
165
+        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
166
+        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
167
+        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
168
+        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
169
+        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
170 170
     esac
171 171
 fi
172 172
 
@@ -175,14 +175,9 @@ save () {
175 175
     for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
176 176
     echo " "
177 177
 }
178
-APP_ARGS=$(save "$@")
178
+APP_ARGS=`save "$@"`
179 179
 
180 180
 # Collect all arguments for the java command, following the shell quoting and substitution rules
181 181
 eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
182 182
 
183
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
184
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
185
-  cd "$(dirname "$0")"
186
-fi
187
-
188 183
 exec "$JAVACMD" "$@"

+ 4
- 1
example/android/gradlew.bat 查看文件

@@ -5,7 +5,7 @@
5 5
 @rem you may not use this file except in compliance with the License.
6 6
 @rem You may obtain a copy of the License at
7 7
 @rem
8
-@rem      http://www.apache.org/licenses/LICENSE-2.0
8
+@rem      https://www.apache.org/licenses/LICENSE-2.0
9 9
 @rem
10 10
 @rem Unless required by applicable law or agreed to in writing, software
11 11
 @rem distributed under the License is distributed on an "AS IS" BASIS,
@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
29 29
 set APP_BASE_NAME=%~n0
30 30
 set APP_HOME=%DIRNAME%
31 31
 
32
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
33
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34
+
32 35
 @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
33 36
 set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
34 37
 

+ 9
- 0
example/android/settings.gradle 查看文件

@@ -3,3 +3,12 @@ include ':app'
3 3
 
4 4
 include ':react-native-safe-area-context'
5 5
 project(':react-native-safe-area-context').projectDir = new File(rootProject.projectDir, '../../android')
6
+
7
+include ':react-native-community-async-storage'
8
+project(':react-native-community-async-storage').projectDir = new File(rootProject.projectDir, '../../node_modules/@react-native-community/async-storage/android')
9
+include ':react-native-gesture-handler'
10
+project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../../node_modules/react-native-gesture-handler/android')
11
+include ':react-native-reanimated'
12
+project(':react-native-reanimated').projectDir = new File(rootProject.projectDir, '../../node_modules/react-native-reanimated/android')
13
+include ':react-native-screens'
14
+project(':react-native-screens').projectDir = new File(rootProject.projectDir, '../../node_modules/react-native-screens/android')

+ 1
- 1
example/app.json 查看文件

@@ -2,7 +2,7 @@
2 2
   "name": "SafeAreaViewExample",
3 3
   "displayName": "SafeAreaViewExample",
4 4
   "expo": {
5
-    "entryPoint": "node_modules/expo/AppEntry",
5
+    "entryPoint": "./example/index.expo",
6 6
     "name": "react-native-safe-area-context",
7 7
     "slug": "react-native-safe-area-context",
8 8
     "version": "0.1.0",

+ 5
- 0
example/index.expo.js 查看文件

@@ -0,0 +1,5 @@
1
+import registerRootComponent from 'expo/build/launch/registerRootComponent';
2
+
3
+import App from './src/App';
4
+
5
+registerRootComponent(App);

+ 1
- 1
example/index.js 查看文件

@@ -1,5 +1,5 @@
1 1
 import { AppRegistry } from 'react-native';
2
-import App from './App';
2
+import App from './src/App';
3 3
 import { name as appName } from './app.json';
4 4
 
5 5
 AppRegistry.registerComponent(appName, () => App);

+ 15
- 32
example/ios/Podfile 查看文件

@@ -1,37 +1,20 @@
1
-platform :ios, '9.0'
1
+$root_path = "../.."
2
+$node_modules = "#{$root_path}/node_modules"
3
+$react_native_path = "#{$node_modules}/react-native"
2 4
 
3
-target 'SafeAreaViewExample' do
4
-  # Pods for SafeAreaViewExample
5
-  pod 'FBLazyVector', :path => "../../node_modules/react-native/Libraries/FBLazyVector"
6
-  pod 'FBReactNativeSpec', :path => "../../node_modules/react-native/Libraries/FBReactNativeSpec"
7
-  pod 'RCTRequired', :path => "../../node_modules/react-native/Libraries/RCTRequired"
8
-  pod 'RCTTypeSafety', :path => "../../node_modules/react-native/Libraries/TypeSafety"
9
-  pod 'React', :path => '../../node_modules/react-native/'
10
-  pod 'React-Core', :path => '../../node_modules/react-native/'
11
-  pod 'React-CoreModules', :path => '../../node_modules/react-native/React/CoreModules'
12
-  pod 'React-Core/DevSupport', :path => '../../node_modules/react-native/'
13
-  pod 'React-RCTActionSheet', :path => '../../node_modules/react-native/Libraries/ActionSheetIOS'
14
-  pod 'React-RCTAnimation', :path => '../../node_modules/react-native/Libraries/NativeAnimation'
15
-  pod 'React-RCTBlob', :path => '../../node_modules/react-native/Libraries/Blob'
16
-  pod 'React-RCTImage', :path => '../../node_modules/react-native/Libraries/Image'
17
-  pod 'React-RCTLinking', :path => '../../node_modules/react-native/Libraries/LinkingIOS'
18
-  pod 'React-RCTNetwork', :path => '../../node_modules/react-native/Libraries/Network'
19
-  pod 'React-RCTSettings', :path => '../../node_modules/react-native/Libraries/Settings'
20
-  pod 'React-RCTText', :path => '../../node_modules/react-native/Libraries/Text'
21
-  pod 'React-RCTVibration', :path => '../../node_modules/react-native/Libraries/Vibration'
22
-  pod 'React-Core/RCTWebSocket', :path => '../../node_modules/react-native/'
5
+require_relative "#{$node_modules}/react-native/scripts/react_native_pods"
6
+require_relative "#{$node_modules}/@react-native-community/cli-platform-ios/native_modules"
23 7
 
24
-  pod 'React-cxxreact', :path => '../../node_modules/react-native/ReactCommon/cxxreact'
25
-  pod 'React-jsi', :path => '../../node_modules/react-native/ReactCommon/jsi'
26
-  pod 'React-jsiexecutor', :path => '../../node_modules/react-native/ReactCommon/jsiexecutor'
27
-  pod 'React-jsinspector', :path => '../../node_modules/react-native/ReactCommon/jsinspector'
28
-  pod 'ReactCommon/jscallinvoker', :path => "../../node_modules/react-native/ReactCommon"
29
-  pod 'ReactCommon/turbomodule/core', :path => "../../node_modules/react-native/ReactCommon"
30
-  pod 'Yoga', :path => '../../node_modules/react-native/ReactCommon/yoga'
8
+platform :ios, "10.0"
31 9
 
32
-  pod 'DoubleConversion', :podspec => '../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
33
-  pod 'glog', :podspec => '../../node_modules/react-native/third-party-podspecs/glog.podspec'
34
-  pod 'Folly', :podspec => '../../node_modules/react-native/third-party-podspecs/Folly.podspec'
10
+target "SafeAreaViewExample" do
11
+  use_react_native!(path: $react_native_path)
35 12
 
36
-  pod 'react-native-safe-area-context', :path => '../../'
13
+  pod "react-native-safe-area-context", :path => $root_path
14
+  pod "RNCAsyncStorage", :path => "#{$node_modules}/@react-native-community/async-storage"
15
+  pod "RNCMaskedView", :path => "#{$node_modules}/@react-native-community/masked-view"
16
+  pod "RNGestureHandler", :path => "#{$node_modules}/react-native-gesture-handler"
17
+  pod "RNReanimated", :path => "#{$node_modules}/react-native-reanimated"
18
+  pod "RNScreens", :path => "#{$node_modules}/react-native-screens"
37 19
 end
20
+

+ 251
- 190
example/ios/Podfile.lock 查看文件

@@ -1,224 +1,262 @@
1 1
 PODS:
2 2
   - boost-for-react-native (1.63.0)
3 3
   - DoubleConversion (1.1.6)
4
-  - FBLazyVector (0.61.5)
5
-  - FBReactNativeSpec (0.61.5):
6
-    - Folly (= 2018.10.22.00)
7
-    - RCTRequired (= 0.61.5)
8
-    - RCTTypeSafety (= 0.61.5)
9
-    - React-Core (= 0.61.5)
10
-    - React-jsi (= 0.61.5)
11
-    - ReactCommon/turbomodule/core (= 0.61.5)
12
-  - Folly (2018.10.22.00):
4
+  - FBLazyVector (0.63.0-rc.0)
5
+  - FBReactNativeSpec (0.63.0-rc.0):
6
+    - Folly (= 2020.01.13.00)
7
+    - RCTRequired (= 0.63.0-rc.0)
8
+    - RCTTypeSafety (= 0.63.0-rc.0)
9
+    - React-Core (= 0.63.0-rc.0)
10
+    - React-jsi (= 0.63.0-rc.0)
11
+    - ReactCommon/turbomodule/core (= 0.63.0-rc.0)
12
+  - Folly (2020.01.13.00):
13 13
     - boost-for-react-native
14 14
     - DoubleConversion
15
-    - Folly/Default (= 2018.10.22.00)
15
+    - Folly/Default (= 2020.01.13.00)
16 16
     - glog
17
-  - Folly/Default (2018.10.22.00):
17
+  - Folly/Default (2020.01.13.00):
18 18
     - boost-for-react-native
19 19
     - DoubleConversion
20 20
     - glog
21 21
   - glog (0.3.5)
22
-  - RCTRequired (0.61.5)
23
-  - RCTTypeSafety (0.61.5):
24
-    - FBLazyVector (= 0.61.5)
25
-    - Folly (= 2018.10.22.00)
26
-    - RCTRequired (= 0.61.5)
27
-    - React-Core (= 0.61.5)
28
-  - React (0.61.5):
29
-    - React-Core (= 0.61.5)
30
-    - React-Core/DevSupport (= 0.61.5)
31
-    - React-Core/RCTWebSocket (= 0.61.5)
32
-    - React-RCTActionSheet (= 0.61.5)
33
-    - React-RCTAnimation (= 0.61.5)
34
-    - React-RCTBlob (= 0.61.5)
35
-    - React-RCTImage (= 0.61.5)
36
-    - React-RCTLinking (= 0.61.5)
37
-    - React-RCTNetwork (= 0.61.5)
38
-    - React-RCTSettings (= 0.61.5)
39
-    - React-RCTText (= 0.61.5)
40
-    - React-RCTVibration (= 0.61.5)
41
-  - React-Core (0.61.5):
42
-    - Folly (= 2018.10.22.00)
22
+  - RCTRequired (0.63.0-rc.0)
23
+  - RCTTypeSafety (0.63.0-rc.0):
24
+    - FBLazyVector (= 0.63.0-rc.0)
25
+    - Folly (= 2020.01.13.00)
26
+    - RCTRequired (= 0.63.0-rc.0)
27
+    - React-Core (= 0.63.0-rc.0)
28
+  - React (0.63.0-rc.0):
29
+    - React-Core (= 0.63.0-rc.0)
30
+    - React-Core/DevSupport (= 0.63.0-rc.0)
31
+    - React-Core/RCTWebSocket (= 0.63.0-rc.0)
32
+    - React-RCTActionSheet (= 0.63.0-rc.0)
33
+    - React-RCTAnimation (= 0.63.0-rc.0)
34
+    - React-RCTBlob (= 0.63.0-rc.0)
35
+    - React-RCTImage (= 0.63.0-rc.0)
36
+    - React-RCTLinking (= 0.63.0-rc.0)
37
+    - React-RCTNetwork (= 0.63.0-rc.0)
38
+    - React-RCTSettings (= 0.63.0-rc.0)
39
+    - React-RCTText (= 0.63.0-rc.0)
40
+    - React-RCTVibration (= 0.63.0-rc.0)
41
+  - React-callinvoker (0.63.0-rc.0)
42
+  - React-Core (0.63.0-rc.0):
43
+    - Folly (= 2020.01.13.00)
43 44
     - glog
44
-    - React-Core/Default (= 0.61.5)
45
-    - React-cxxreact (= 0.61.5)
46
-    - React-jsi (= 0.61.5)
47
-    - React-jsiexecutor (= 0.61.5)
45
+    - React-Core/Default (= 0.63.0-rc.0)
46
+    - React-cxxreact (= 0.63.0-rc.0)
47
+    - React-jsi (= 0.63.0-rc.0)
48
+    - React-jsiexecutor (= 0.63.0-rc.0)
48 49
     - Yoga
49
-  - React-Core/CoreModulesHeaders (0.61.5):
50
-    - Folly (= 2018.10.22.00)
50
+  - React-Core/CoreModulesHeaders (0.63.0-rc.0):
51
+    - Folly (= 2020.01.13.00)
51 52
     - glog
52 53
     - React-Core/Default
53
-    - React-cxxreact (= 0.61.5)
54
-    - React-jsi (= 0.61.5)
55
-    - React-jsiexecutor (= 0.61.5)
54
+    - React-cxxreact (= 0.63.0-rc.0)
55
+    - React-jsi (= 0.63.0-rc.0)
56
+    - React-jsiexecutor (= 0.63.0-rc.0)
56 57
     - Yoga
57
-  - React-Core/Default (0.61.5):
58
-    - Folly (= 2018.10.22.00)
58
+  - React-Core/Default (0.63.0-rc.0):
59
+    - Folly (= 2020.01.13.00)
59 60
     - glog
60
-    - React-cxxreact (= 0.61.5)
61
-    - React-jsi (= 0.61.5)
62
-    - React-jsiexecutor (= 0.61.5)
61
+    - React-cxxreact (= 0.63.0-rc.0)
62
+    - React-jsi (= 0.63.0-rc.0)
63
+    - React-jsiexecutor (= 0.63.0-rc.0)
63 64
     - Yoga
64
-  - React-Core/DevSupport (0.61.5):
65
-    - Folly (= 2018.10.22.00)
65
+  - React-Core/DevSupport (0.63.0-rc.0):
66
+    - Folly (= 2020.01.13.00)
66 67
     - glog
67
-    - React-Core/Default (= 0.61.5)
68
-    - React-Core/RCTWebSocket (= 0.61.5)
69
-    - React-cxxreact (= 0.61.5)
70
-    - React-jsi (= 0.61.5)
71
-    - React-jsiexecutor (= 0.61.5)
72
-    - React-jsinspector (= 0.61.5)
68
+    - React-Core/Default (= 0.63.0-rc.0)
69
+    - React-Core/RCTWebSocket (= 0.63.0-rc.0)
70
+    - React-cxxreact (= 0.63.0-rc.0)
71
+    - React-jsi (= 0.63.0-rc.0)
72
+    - React-jsiexecutor (= 0.63.0-rc.0)
73
+    - React-jsinspector (= 0.63.0-rc.0)
73 74
     - Yoga
74
-  - React-Core/RCTActionSheetHeaders (0.61.5):
75
-    - Folly (= 2018.10.22.00)
75
+  - React-Core/RCTActionSheetHeaders (0.63.0-rc.0):
76
+    - Folly (= 2020.01.13.00)
76 77
     - glog
77 78
     - React-Core/Default
78
-    - React-cxxreact (= 0.61.5)
79
-    - React-jsi (= 0.61.5)
80
-    - React-jsiexecutor (= 0.61.5)
79
+    - React-cxxreact (= 0.63.0-rc.0)
80
+    - React-jsi (= 0.63.0-rc.0)
81
+    - React-jsiexecutor (= 0.63.0-rc.0)
81 82
     - Yoga
82
-  - React-Core/RCTAnimationHeaders (0.61.5):
83
-    - Folly (= 2018.10.22.00)
83
+  - React-Core/RCTAnimationHeaders (0.63.0-rc.0):
84
+    - Folly (= 2020.01.13.00)
84 85
     - glog
85 86
     - React-Core/Default
86
-    - React-cxxreact (= 0.61.5)
87
-    - React-jsi (= 0.61.5)
88
-    - React-jsiexecutor (= 0.61.5)
87
+    - React-cxxreact (= 0.63.0-rc.0)
88
+    - React-jsi (= 0.63.0-rc.0)
89
+    - React-jsiexecutor (= 0.63.0-rc.0)
89 90
     - Yoga
90
-  - React-Core/RCTBlobHeaders (0.61.5):
91
-    - Folly (= 2018.10.22.00)
91
+  - React-Core/RCTBlobHeaders (0.63.0-rc.0):
92
+    - Folly (= 2020.01.13.00)
92 93
     - glog
93 94
     - React-Core/Default
94
-    - React-cxxreact (= 0.61.5)
95
-    - React-jsi (= 0.61.5)
96
-    - React-jsiexecutor (= 0.61.5)
95
+    - React-cxxreact (= 0.63.0-rc.0)
96
+    - React-jsi (= 0.63.0-rc.0)
97
+    - React-jsiexecutor (= 0.63.0-rc.0)
97 98
     - Yoga
98
-  - React-Core/RCTImageHeaders (0.61.5):
99
-    - Folly (= 2018.10.22.00)
99
+  - React-Core/RCTImageHeaders (0.63.0-rc.0):
100
+    - Folly (= 2020.01.13.00)
100 101
     - glog
101 102
     - React-Core/Default
102
-    - React-cxxreact (= 0.61.5)
103
-    - React-jsi (= 0.61.5)
104
-    - React-jsiexecutor (= 0.61.5)
103
+    - React-cxxreact (= 0.63.0-rc.0)
104
+    - React-jsi (= 0.63.0-rc.0)
105
+    - React-jsiexecutor (= 0.63.0-rc.0)
105 106
     - Yoga
106
-  - React-Core/RCTLinkingHeaders (0.61.5):
107
-    - Folly (= 2018.10.22.00)
107
+  - React-Core/RCTLinkingHeaders (0.63.0-rc.0):
108
+    - Folly (= 2020.01.13.00)
108 109
     - glog
109 110
     - React-Core/Default
110
-    - React-cxxreact (= 0.61.5)
111
-    - React-jsi (= 0.61.5)
112
-    - React-jsiexecutor (= 0.61.5)
111
+    - React-cxxreact (= 0.63.0-rc.0)
112
+    - React-jsi (= 0.63.0-rc.0)
113
+    - React-jsiexecutor (= 0.63.0-rc.0)
113 114
     - Yoga
114
-  - React-Core/RCTNetworkHeaders (0.61.5):
115
-    - Folly (= 2018.10.22.00)
115
+  - React-Core/RCTNetworkHeaders (0.63.0-rc.0):
116
+    - Folly (= 2020.01.13.00)
116 117
     - glog
117 118
     - React-Core/Default
118
-    - React-cxxreact (= 0.61.5)
119
-    - React-jsi (= 0.61.5)
120
-    - React-jsiexecutor (= 0.61.5)
119
+    - React-cxxreact (= 0.63.0-rc.0)
120
+    - React-jsi (= 0.63.0-rc.0)
121
+    - React-jsiexecutor (= 0.63.0-rc.0)
121 122
     - Yoga
122
-  - React-Core/RCTSettingsHeaders (0.61.5):
123
-    - Folly (= 2018.10.22.00)
123
+  - React-Core/RCTSettingsHeaders (0.63.0-rc.0):
124
+    - Folly (= 2020.01.13.00)
124 125
     - glog
125 126
     - React-Core/Default
126
-    - React-cxxreact (= 0.61.5)
127
-    - React-jsi (= 0.61.5)
128
-    - React-jsiexecutor (= 0.61.5)
127
+    - React-cxxreact (= 0.63.0-rc.0)
128
+    - React-jsi (= 0.63.0-rc.0)
129
+    - React-jsiexecutor (= 0.63.0-rc.0)
129 130
     - Yoga
130
-  - React-Core/RCTTextHeaders (0.61.5):
131
-    - Folly (= 2018.10.22.00)
131
+  - React-Core/RCTTextHeaders (0.63.0-rc.0):
132
+    - Folly (= 2020.01.13.00)
132 133
     - glog
133 134
     - React-Core/Default
134
-    - React-cxxreact (= 0.61.5)
135
-    - React-jsi (= 0.61.5)
136
-    - React-jsiexecutor (= 0.61.5)
135
+    - React-cxxreact (= 0.63.0-rc.0)
136
+    - React-jsi (= 0.63.0-rc.0)
137
+    - React-jsiexecutor (= 0.63.0-rc.0)
137 138
     - Yoga
138
-  - React-Core/RCTVibrationHeaders (0.61.5):
139
-    - Folly (= 2018.10.22.00)
139
+  - React-Core/RCTVibrationHeaders (0.63.0-rc.0):
140
+    - Folly (= 2020.01.13.00)
140 141
     - glog
141 142
     - React-Core/Default
142
-    - React-cxxreact (= 0.61.5)
143
-    - React-jsi (= 0.61.5)
144
-    - React-jsiexecutor (= 0.61.5)
143
+    - React-cxxreact (= 0.63.0-rc.0)
144
+    - React-jsi (= 0.63.0-rc.0)
145
+    - React-jsiexecutor (= 0.63.0-rc.0)
145 146
     - Yoga
146
-  - React-Core/RCTWebSocket (0.61.5):
147
-    - Folly (= 2018.10.22.00)
147
+  - React-Core/RCTWebSocket (0.63.0-rc.0):
148
+    - Folly (= 2020.01.13.00)
148 149
     - glog
149
-    - React-Core/Default (= 0.61.5)
150
-    - React-cxxreact (= 0.61.5)
151
-    - React-jsi (= 0.61.5)
152
-    - React-jsiexecutor (= 0.61.5)
150
+    - React-Core/Default (= 0.63.0-rc.0)
151
+    - React-cxxreact (= 0.63.0-rc.0)
152
+    - React-jsi (= 0.63.0-rc.0)
153
+    - React-jsiexecutor (= 0.63.0-rc.0)
153 154
     - Yoga
154
-  - React-CoreModules (0.61.5):
155
-    - FBReactNativeSpec (= 0.61.5)
156
-    - Folly (= 2018.10.22.00)
157
-    - RCTTypeSafety (= 0.61.5)
158
-    - React-Core/CoreModulesHeaders (= 0.61.5)
159
-    - React-RCTImage (= 0.61.5)
160
-    - ReactCommon/turbomodule/core (= 0.61.5)
161
-  - React-cxxreact (0.61.5):
155
+  - React-CoreModules (0.63.0-rc.0):
156
+    - FBReactNativeSpec (= 0.63.0-rc.0)
157
+    - Folly (= 2020.01.13.00)
158
+    - RCTTypeSafety (= 0.63.0-rc.0)
159
+    - React-Core/CoreModulesHeaders (= 0.63.0-rc.0)
160
+    - React-jsi (= 0.63.0-rc.0)
161
+    - React-RCTImage (= 0.63.0-rc.0)
162
+    - ReactCommon/turbomodule/core (= 0.63.0-rc.0)
163
+  - React-cxxreact (0.63.0-rc.0):
162 164
     - boost-for-react-native (= 1.63.0)
163 165
     - DoubleConversion
164
-    - Folly (= 2018.10.22.00)
166
+    - Folly (= 2020.01.13.00)
165 167
     - glog
166
-    - React-jsinspector (= 0.61.5)
167
-  - React-jsi (0.61.5):
168
+    - React-callinvoker (= 0.63.0-rc.0)
169
+    - React-jsinspector (= 0.63.0-rc.0)
170
+  - React-jsi (0.63.0-rc.0):
168 171
     - boost-for-react-native (= 1.63.0)
169 172
     - DoubleConversion
170
-    - Folly (= 2018.10.22.00)
173
+    - Folly (= 2020.01.13.00)
171 174
     - glog
172
-    - React-jsi/Default (= 0.61.5)
173
-  - React-jsi/Default (0.61.5):
175
+    - React-jsi/Default (= 0.63.0-rc.0)
176
+  - React-jsi/Default (0.63.0-rc.0):
174 177
     - boost-for-react-native (= 1.63.0)
175 178
     - DoubleConversion
176
-    - Folly (= 2018.10.22.00)
179
+    - Folly (= 2020.01.13.00)
177 180
     - glog
178
-  - React-jsiexecutor (0.61.5):
181
+  - React-jsiexecutor (0.63.0-rc.0):
179 182
     - DoubleConversion
180
-    - Folly (= 2018.10.22.00)
183
+    - Folly (= 2020.01.13.00)
181 184
     - glog
182
-    - React-cxxreact (= 0.61.5)
183
-    - React-jsi (= 0.61.5)
184
-  - React-jsinspector (0.61.5)
185
-  - react-native-safe-area-context (0.6.4):
185
+    - React-cxxreact (= 0.63.0-rc.0)
186
+    - React-jsi (= 0.63.0-rc.0)
187
+  - React-jsinspector (0.63.0-rc.0)
188
+  - react-native-safe-area-context (1.0.0):
186 189
     - React
187
-  - React-RCTActionSheet (0.61.5):
188
-    - React-Core/RCTActionSheetHeaders (= 0.61.5)
189
-  - React-RCTAnimation (0.61.5):
190
-    - React-Core/RCTAnimationHeaders (= 0.61.5)
191
-  - React-RCTBlob (0.61.5):
192
-    - React-Core/RCTBlobHeaders (= 0.61.5)
193
-    - React-Core/RCTWebSocket (= 0.61.5)
194
-    - React-jsi (= 0.61.5)
195
-    - React-RCTNetwork (= 0.61.5)
196
-  - React-RCTImage (0.61.5):
197
-    - React-Core/RCTImageHeaders (= 0.61.5)
198
-    - React-RCTNetwork (= 0.61.5)
199
-  - React-RCTLinking (0.61.5):
200
-    - React-Core/RCTLinkingHeaders (= 0.61.5)
201
-  - React-RCTNetwork (0.61.5):
202
-    - React-Core/RCTNetworkHeaders (= 0.61.5)
203
-  - React-RCTSettings (0.61.5):
204
-    - React-Core/RCTSettingsHeaders (= 0.61.5)
205
-  - React-RCTText (0.61.5):
206
-    - React-Core/RCTTextHeaders (= 0.61.5)
207
-  - React-RCTVibration (0.61.5):
208
-    - React-Core/RCTVibrationHeaders (= 0.61.5)
209
-  - ReactCommon/jscallinvoker (0.61.5):
190
+  - React-RCTActionSheet (0.63.0-rc.0):
191
+    - React-Core/RCTActionSheetHeaders (= 0.63.0-rc.0)
192
+  - React-RCTAnimation (0.63.0-rc.0):
193
+    - FBReactNativeSpec (= 0.63.0-rc.0)
194
+    - Folly (= 2020.01.13.00)
195
+    - RCTTypeSafety (= 0.63.0-rc.0)
196
+    - React-Core/RCTAnimationHeaders (= 0.63.0-rc.0)
197
+    - React-jsi (= 0.63.0-rc.0)
198
+    - ReactCommon/turbomodule/core (= 0.63.0-rc.0)
199
+  - React-RCTBlob (0.63.0-rc.0):
200
+    - FBReactNativeSpec (= 0.63.0-rc.0)
201
+    - Folly (= 2020.01.13.00)
202
+    - React-Core/RCTBlobHeaders (= 0.63.0-rc.0)
203
+    - React-Core/RCTWebSocket (= 0.63.0-rc.0)
204
+    - React-jsi (= 0.63.0-rc.0)
205
+    - React-RCTNetwork (= 0.63.0-rc.0)
206
+    - ReactCommon/turbomodule/core (= 0.63.0-rc.0)
207
+  - React-RCTImage (0.63.0-rc.0):
208
+    - FBReactNativeSpec (= 0.63.0-rc.0)
209
+    - Folly (= 2020.01.13.00)
210
+    - RCTTypeSafety (= 0.63.0-rc.0)
211
+    - React-Core/RCTImageHeaders (= 0.63.0-rc.0)
212
+    - React-jsi (= 0.63.0-rc.0)
213
+    - React-RCTNetwork (= 0.63.0-rc.0)
214
+    - ReactCommon/turbomodule/core (= 0.63.0-rc.0)
215
+  - React-RCTLinking (0.63.0-rc.0):
216
+    - FBReactNativeSpec (= 0.63.0-rc.0)
217
+    - React-Core/RCTLinkingHeaders (= 0.63.0-rc.0)
218
+    - React-jsi (= 0.63.0-rc.0)
219
+    - ReactCommon/turbomodule/core (= 0.63.0-rc.0)
220
+  - React-RCTNetwork (0.63.0-rc.0):
221
+    - FBReactNativeSpec (= 0.63.0-rc.0)
222
+    - Folly (= 2020.01.13.00)
223
+    - RCTTypeSafety (= 0.63.0-rc.0)
224
+    - React-Core/RCTNetworkHeaders (= 0.63.0-rc.0)
225
+    - React-jsi (= 0.63.0-rc.0)
226
+    - ReactCommon/turbomodule/core (= 0.63.0-rc.0)
227
+  - React-RCTSettings (0.63.0-rc.0):
228
+    - FBReactNativeSpec (= 0.63.0-rc.0)
229
+    - Folly (= 2020.01.13.00)
230
+    - RCTTypeSafety (= 0.63.0-rc.0)
231
+    - React-Core/RCTSettingsHeaders (= 0.63.0-rc.0)
232
+    - React-jsi (= 0.63.0-rc.0)
233
+    - ReactCommon/turbomodule/core (= 0.63.0-rc.0)
234
+  - React-RCTText (0.63.0-rc.0):
235
+    - React-Core/RCTTextHeaders (= 0.63.0-rc.0)
236
+  - React-RCTVibration (0.63.0-rc.0):
237
+    - FBReactNativeSpec (= 0.63.0-rc.0)
238
+    - Folly (= 2020.01.13.00)
239
+    - React-Core/RCTVibrationHeaders (= 0.63.0-rc.0)
240
+    - React-jsi (= 0.63.0-rc.0)
241
+    - ReactCommon/turbomodule/core (= 0.63.0-rc.0)
242
+  - ReactCommon/turbomodule/core (0.63.0-rc.0):
210 243
     - DoubleConversion
211
-    - Folly (= 2018.10.22.00)
244
+    - Folly (= 2020.01.13.00)
212 245
     - glog
213
-    - React-cxxreact (= 0.61.5)
214
-  - ReactCommon/turbomodule/core (0.61.5):
215
-    - DoubleConversion
216
-    - Folly (= 2018.10.22.00)
217
-    - glog
218
-    - React-Core (= 0.61.5)
219
-    - React-cxxreact (= 0.61.5)
220
-    - React-jsi (= 0.61.5)
221
-    - ReactCommon/jscallinvoker (= 0.61.5)
246
+    - React-callinvoker (= 0.63.0-rc.0)
247
+    - React-Core (= 0.63.0-rc.0)
248
+    - React-cxxreact (= 0.63.0-rc.0)
249
+    - React-jsi (= 0.63.0-rc.0)
250
+  - RNCAsyncStorage (1.10.1):
251
+    - React
252
+  - RNCMaskedView (0.1.10):
253
+    - React
254
+  - RNGestureHandler (1.6.1):
255
+    - React
256
+  - RNReanimated (1.8.0):
257
+    - React
258
+  - RNScreens (2.7.0):
259
+    - React
222 260
   - Yoga (1.14.0)
223 261
 
224 262
 DEPENDENCIES:
@@ -230,6 +268,7 @@ DEPENDENCIES:
230 268
   - RCTRequired (from `../../node_modules/react-native/Libraries/RCTRequired`)
231 269
   - RCTTypeSafety (from `../../node_modules/react-native/Libraries/TypeSafety`)
232 270
   - React (from `../../node_modules/react-native/`)
271
+  - React-callinvoker (from `../../node_modules/react-native/ReactCommon/callinvoker`)
233 272
   - React-Core (from `../../node_modules/react-native/`)
234 273
   - React-Core/DevSupport (from `../../node_modules/react-native/`)
235 274
   - React-Core/RCTWebSocket (from `../../node_modules/react-native/`)
@@ -238,7 +277,7 @@ DEPENDENCIES:
238 277
   - React-jsi (from `../../node_modules/react-native/ReactCommon/jsi`)
239 278
   - React-jsiexecutor (from `../../node_modules/react-native/ReactCommon/jsiexecutor`)
240 279
   - React-jsinspector (from `../../node_modules/react-native/ReactCommon/jsinspector`)
241
-  - react-native-safe-area-context (from `../../`)
280
+  - react-native-safe-area-context (from `../..`)
242 281
   - React-RCTActionSheet (from `../../node_modules/react-native/Libraries/ActionSheetIOS`)
243 282
   - React-RCTAnimation (from `../../node_modules/react-native/Libraries/NativeAnimation`)
244 283
   - React-RCTBlob (from `../../node_modules/react-native/Libraries/Blob`)
@@ -248,8 +287,12 @@ DEPENDENCIES:
248 287
   - React-RCTSettings (from `../../node_modules/react-native/Libraries/Settings`)
249 288
   - React-RCTText (from `../../node_modules/react-native/Libraries/Text`)
250 289
   - React-RCTVibration (from `../../node_modules/react-native/Libraries/Vibration`)
251
-  - ReactCommon/jscallinvoker (from `../../node_modules/react-native/ReactCommon`)
252 290
   - ReactCommon/turbomodule/core (from `../../node_modules/react-native/ReactCommon`)
291
+  - "RNCAsyncStorage (from `../../node_modules/@react-native-community/async-storage`)"
292
+  - "RNCMaskedView (from `../../node_modules/@react-native-community/masked-view`)"
293
+  - RNGestureHandler (from `../../node_modules/react-native-gesture-handler`)
294
+  - RNReanimated (from `../../node_modules/react-native-reanimated`)
295
+  - RNScreens (from `../../node_modules/react-native-screens`)
253 296
   - Yoga (from `../../node_modules/react-native/ReactCommon/yoga`)
254 297
 
255 298
 SPEC REPOS:
@@ -273,6 +316,8 @@ EXTERNAL SOURCES:
273 316
     :path: "../../node_modules/react-native/Libraries/TypeSafety"
274 317
   React:
275 318
     :path: "../../node_modules/react-native/"
319
+  React-callinvoker:
320
+    :path: "../../node_modules/react-native/ReactCommon/callinvoker"
276 321
   React-Core:
277 322
     :path: "../../node_modules/react-native/"
278 323
   React-CoreModules:
@@ -286,7 +331,7 @@ EXTERNAL SOURCES:
286 331
   React-jsinspector:
287 332
     :path: "../../node_modules/react-native/ReactCommon/jsinspector"
288 333
   react-native-safe-area-context:
289
-    :path: "../../"
334
+    :path: "../.."
290 335
   React-RCTActionSheet:
291 336
     :path: "../../node_modules/react-native/Libraries/ActionSheetIOS"
292 337
   React-RCTAnimation:
@@ -307,38 +352,54 @@ EXTERNAL SOURCES:
307 352
     :path: "../../node_modules/react-native/Libraries/Vibration"
308 353
   ReactCommon:
309 354
     :path: "../../node_modules/react-native/ReactCommon"
355
+  RNCAsyncStorage:
356
+    :path: "../../node_modules/@react-native-community/async-storage"
357
+  RNCMaskedView:
358
+    :path: "../../node_modules/@react-native-community/masked-view"
359
+  RNGestureHandler:
360
+    :path: "../../node_modules/react-native-gesture-handler"
361
+  RNReanimated:
362
+    :path: "../../node_modules/react-native-reanimated"
363
+  RNScreens:
364
+    :path: "../../node_modules/react-native-screens"
310 365
   Yoga:
311 366
     :path: "../../node_modules/react-native/ReactCommon/yoga"
312 367
 
313 368
 SPEC CHECKSUMS:
314 369
   boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
315
-  DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
316
-  FBLazyVector: aaeaf388755e4f29cd74acbc9e3b8da6d807c37f
317
-  FBReactNativeSpec: 118d0d177724c2d67f08a59136eb29ef5943ec75
318
-  Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
319
-  glog: 1f3da668190260b06b429bb211bfbee5cd790c28
320
-  RCTRequired: b153add4da6e7dbc44aebf93f3cf4fcae392ddf1
321
-  RCTTypeSafety: 9aa1b91d7f9310fc6eadc3cf95126ffe818af320
322
-  React: b6a59ef847b2b40bb6e0180a97d0ca716969ac78
323
-  React-Core: 688b451f7d616cc1134ac95295b593d1b5158a04
324
-  React-CoreModules: d04f8494c1a328b69ec11db9d1137d667f916dcb
325
-  React-cxxreact: d0f7bcafa196ae410e5300736b424455e7fb7ba7
326
-  React-jsi: cb2cd74d7ccf4cffb071a46833613edc79cdf8f7
327
-  React-jsiexecutor: d5525f9ed5f782fdbacb64b9b01a43a9323d2386
328
-  React-jsinspector: fa0ecc501688c3c4c34f28834a76302233e29dc0
329
-  react-native-safe-area-context: 52342d2d80ea8faadd0ffa76d83b6051f20c5329
330
-  React-RCTActionSheet: 600b4d10e3aea0913b5a92256d2719c0cdd26d76
331
-  React-RCTAnimation: 791a87558389c80908ed06cc5dfc5e7920dfa360
332
-  React-RCTBlob: d89293cc0236d9cb0933d85e430b0bbe81ad1d72
333
-  React-RCTImage: 6b8e8df449eb7c814c99a92d6b52de6fe39dea4e
334
-  React-RCTLinking: 121bb231c7503cf9094f4d8461b96a130fabf4a5
335
-  React-RCTNetwork: fb353640aafcee84ca8b78957297bd395f065c9a
336
-  React-RCTSettings: 8db258ea2a5efee381fcf7a6d5044e2f8b68b640
337
-  React-RCTText: 9ccc88273e9a3aacff5094d2175a605efa854dbe
338
-  React-RCTVibration: a49a1f42bf8f5acf1c3e297097517c6b3af377ad
339
-  ReactCommon: 198c7c8d3591f975e5431bec1b0b3b581aa1c5dd
340
-  Yoga: f2a7cd4280bfe2cca5a7aed98ba0eb3d1310f18b
370
+  DoubleConversion: cde416483dac037923206447da6e1454df403714
371
+  FBLazyVector: 78609f00baec7c48492967441897aa8cee25a612
372
+  FBReactNativeSpec: 78b0d7c0ecca12a7306ce8c04f041bc358c60beb
373
+  Folly: b73c3869541e86821df3c387eb0af5f65addfab4
374
+  glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
375
+  RCTRequired: c5302fd1e3225d47b041121363398dc265a964ac
376
+  RCTTypeSafety: a42f9e52df553d6bdc3a007376e948252f250cba
377
+  React: 6c9152bc1b9fefba67ca0344c6e242f01039dd6b
378
+  React-callinvoker: 99716fad454984727741acd315e653385869b592
379
+  React-Core: 548f0e70be73b463b16acf6a05c1668ab1dc9697
380
+  React-CoreModules: 814839144329ae12bf51a3e87938e77e205e6915
381
+  React-cxxreact: 3c30dbf55f1d1847a3c7e140f249a0c4a296d93e
382
+  React-jsi: 87b6b899f6c81c29487d0416969c261b73f46a2d
383
+  React-jsiexecutor: 0ca3a8a0a65f9eb9aec3273c4cf44f6d31277937
384
+  React-jsinspector: 09b8cb3fefdf81b2889a13cc1a645e905e514ddb
385
+  react-native-safe-area-context: a346c75f2288147527365ce27b59ca6d38c27805
386
+  React-RCTActionSheet: b6d2445d7317359997ed0c650421d0a0b9dd58cb
387
+  React-RCTAnimation: 2f48bd93a4f5317cd5ab7189c6b5e469b60fb7bf
388
+  React-RCTBlob: b8da9c90135ee183f3ad35b521313390370b5ed2
389
+  React-RCTImage: 705db0bdff4609796e8548716ce19a34488bb7a3
390
+  React-RCTLinking: ecc90e00cc0604ddb2276d828c6227a7251eaa5e
391
+  React-RCTNetwork: b05b4e09038cac3e63b7ddbdac0d7abb8e18655d
392
+  React-RCTSettings: bbd1601b51a6475157bc03f39d6378ce15ed0954
393
+  React-RCTText: 32e3c891fa74b1b2544517e59ee5fbc96f672983
394
+  React-RCTVibration: ab7fb7b10ca373d7e931b15e18b5f6d1663367ca
395
+  ReactCommon: 14ae20c83bd846c1790e45ad95e0f0717dcd034f
396
+  RNCAsyncStorage: 39831e0dc5f547a1fb2669eb9e091d460a9be2be
397
+  RNCMaskedView: 5a8ec07677aa885546a0d98da336457e2bea557f
398
+  RNGestureHandler: 8f09cd560f8d533eb36da5a6c5a843af9f056b38
399
+  RNReanimated: 955cf4068714003d2f1a6e2bae3fb1118f359aff
400
+  RNScreens: cf198f915f8a2bf163de94ca9f5bfc8d326c3706
401
+  Yoga: 5ffb724bde6d20a1828a1dc9a368085f404a1203
341 402
 
342
-PODFILE CHECKSUM: 3385dd94e97e53501bf5b4afd25375c777edd67d
403
+PODFILE CHECKSUM: 90edcd974101399fc4c4cb2f6ffd1ccb481b16ff
343 404
 
344
-COCOAPODS: 1.8.4
405
+COCOAPODS: 1.9.1

+ 4
- 0
example/ios/SafeAreaViewExample-Bridging-Header.h 查看文件

@@ -0,0 +1,4 @@
1
+//
2
+//  Use this file to import your target's public headers that you would like to expose to Swift.
3
+//
4
+

+ 0
- 53
example/ios/SafeAreaViewExample-tvOS/Info.plist 查看文件

@@ -1,53 +0,0 @@
1
-<?xml version="1.0" encoding="UTF-8"?>
2
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
-<plist version="1.0">
4
-<dict>
5
-	<key>CFBundleDevelopmentRegion</key>
6
-	<string>en</string>
7
-	<key>CFBundleExecutable</key>
8
-	<string>$(EXECUTABLE_NAME)</string>
9
-	<key>CFBundleIdentifier</key>
10
-	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11
-	<key>CFBundleInfoDictionaryVersion</key>
12
-	<string>6.0</string>
13
-	<key>CFBundleName</key>
14
-	<string>$(PRODUCT_NAME)</string>
15
-	<key>CFBundlePackageType</key>
16
-	<string>APPL</string>
17
-	<key>CFBundleShortVersionString</key>
18
-	<string>1.0</string>
19
-	<key>CFBundleSignature</key>
20
-	<string>????</string>
21
-	<key>CFBundleVersion</key>
22
-	<string>1</string>
23
-	<key>LSRequiresIPhoneOS</key>
24
-	<true/>
25
-	<key>NSAppTransportSecurity</key>
26
-	<dict>
27
-		<key>NSExceptionDomains</key>
28
-		<dict>
29
-			<key>localhost</key>
30
-			<dict>
31
-				<key>NSExceptionAllowsInsecureHTTPLoads</key>
32
-				<true/>
33
-			</dict>
34
-		</dict>
35
-	</dict>
36
-	<key>NSLocationWhenInUseUsageDescription</key>
37
-	<string></string>
38
-	<key>UILaunchStoryboardName</key>
39
-	<string>LaunchScreen</string>
40
-	<key>UIRequiredDeviceCapabilities</key>
41
-	<array>
42
-		<string>armv7</string>
43
-	</array>
44
-	<key>UISupportedInterfaceOrientations</key>
45
-	<array>
46
-		<string>UIInterfaceOrientationPortrait</string>
47
-		<string>UIInterfaceOrientationLandscapeLeft</string>
48
-		<string>UIInterfaceOrientationLandscapeRight</string>
49
-	</array>
50
-	<key>UIViewControllerBasedStatusBarAppearance</key>
51
-	<false/>
52
-</dict>
53
-</plist>

+ 0
- 24
example/ios/SafeAreaViewExample-tvOSTests/Info.plist 查看文件

@@ -1,24 +0,0 @@
1
-<?xml version="1.0" encoding="UTF-8"?>
2
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
-<plist version="1.0">
4
-<dict>
5
-	<key>CFBundleDevelopmentRegion</key>
6
-	<string>en</string>
7
-	<key>CFBundleExecutable</key>
8
-	<string>$(EXECUTABLE_NAME)</string>
9
-	<key>CFBundleIdentifier</key>
10
-	<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
11
-	<key>CFBundleInfoDictionaryVersion</key>
12
-	<string>6.0</string>
13
-	<key>CFBundleName</key>
14
-	<string>$(PRODUCT_NAME)</string>
15
-	<key>CFBundlePackageType</key>
16
-	<string>BNDL</string>
17
-	<key>CFBundleShortVersionString</key>
18
-	<string>1.0</string>
19
-	<key>CFBundleSignature</key>
20
-	<string>????</string>
21
-	<key>CFBundleVersion</key>
22
-	<string>1</string>
23
-</dict>
24
-</plist>

+ 47
- 2
example/ios/SafeAreaViewExample.xcodeproj/project.pbxproj 查看文件

@@ -11,6 +11,7 @@
11 11
 		13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
12 12
 		13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13 13
 		13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
14
+		19CA4076245DE96A00FEEC94 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19CA4075245DE96A00FEEC94 /* File.swift */; };
14 15
 		D590E4D001221F6B5AF11381 /* libPods-SafeAreaViewExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 275F94A75481D4E6C652CF4F /* libPods-SafeAreaViewExample.a */; };
15 16
 /* End PBXBuildFile section */
16 17
 
@@ -24,6 +25,8 @@
24 25
 		13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = SafeAreaViewExample/Images.xcassets; sourceTree = "<group>"; };
25 26
 		13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = SafeAreaViewExample/Info.plist; sourceTree = "<group>"; };
26 27
 		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = SafeAreaViewExample/main.m; sourceTree = "<group>"; };
28
+		19CA4074245DE96A00FEEC94 /* SafeAreaViewExample-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SafeAreaViewExample-Bridging-Header.h"; sourceTree = "<group>"; };
29
+		19CA4075245DE96A00FEEC94 /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = File.swift; path = SafeAreaViewExample/File.swift; sourceTree = "<group>"; };
27 30
 		275F94A75481D4E6C652CF4F /* libPods-SafeAreaViewExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SafeAreaViewExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
28 31
 		69AAEDE94ED39E6A720417AA /* Pods-SafeAreaViewExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SafeAreaViewExample.release.xcconfig"; path = "Target Support Files/Pods-SafeAreaViewExample/Pods-SafeAreaViewExample.release.xcconfig"; sourceTree = "<group>"; };
29 32
 		ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
@@ -52,6 +55,8 @@
52 55
 				13B07FB61A68108700A75B9A /* Info.plist */,
53 56
 				13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
54 57
 				13B07FB71A68108700A75B9A /* main.m */,
58
+				19CA4075245DE96A00FEEC94 /* File.swift */,
59
+				19CA4074245DE96A00FEEC94 /* SafeAreaViewExample-Bridging-Header.h */,
55 60
 			);
56 61
 			name = SafeAreaViewExample;
57 62
 			sourceTree = "<group>";
@@ -117,6 +122,7 @@
117 122
 				13B07F8C1A680F5B00A75B9A /* Frameworks */,
118 123
 				13B07F8E1A680F5B00A75B9A /* Resources */,
119 124
 				00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
125
+				9C3A0F31C8045DB6E6F56F79 /* [CP] Copy Pods Resources */,
120 126
 			);
121 127
 			buildRules = (
122 128
 			);
@@ -133,8 +139,13 @@
133 139
 		83CBB9F71A601CBA00E9B192 /* Project object */ = {
134 140
 			isa = PBXProject;
135 141
 			attributes = {
136
-				LastUpgradeCheck = 1030;
142
+				LastUpgradeCheck = 1140;
137 143
 				ORGANIZATIONNAME = Facebook;
144
+				TargetAttributes = {
145
+					13B07F861A680F5B00A75B9A = {
146
+						LastSwiftMigration = 1140;
147
+					};
148
+				};
138 149
 			};
139 150
 			buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "SafeAreaViewExample" */;
140 151
 			compatibilityVersion = "Xcode 3.2";
@@ -203,6 +214,24 @@
203 214
 			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
204 215
 			showEnvVarsInLog = 0;
205 216
 		};
217
+		9C3A0F31C8045DB6E6F56F79 /* [CP] Copy Pods Resources */ = {
218
+			isa = PBXShellScriptBuildPhase;
219
+			buildActionMask = 2147483647;
220
+			files = (
221
+			);
222
+			inputPaths = (
223
+				"${PODS_ROOT}/Target Support Files/Pods-SafeAreaViewExample/Pods-SafeAreaViewExample-resources.sh",
224
+				"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
225
+			);
226
+			name = "[CP] Copy Pods Resources";
227
+			outputPaths = (
228
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
229
+			);
230
+			runOnlyForDeploymentPostprocessing = 0;
231
+			shellPath = /bin/sh;
232
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SafeAreaViewExample/Pods-SafeAreaViewExample-resources.sh\"\n";
233
+			showEnvVarsInLog = 0;
234
+		};
206 235
 		FD10A7F022414F080027D42C /* Start Packager */ = {
207 236
 			isa = PBXShellScriptBuildPhase;
208 237
 			buildActionMask = 2147483647;
@@ -219,7 +248,7 @@
219 248
 			);
220 249
 			runOnlyForDeploymentPostprocessing = 0;
221 250
 			shellPath = /bin/sh;
222
-			shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n  if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n    if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n      echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n      exit 2\n    fi\n  else\n    open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n  fi\nfi\n";
251
+			shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n  if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n    if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n      echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n      exit 2\n    fi\n  else\n    open \"$SRCROOT/../../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n  fi\nfi\n";
223 252
 			showEnvVarsInLog = 0;
224 253
 		};
225 254
 /* End PBXShellScriptBuildPhase section */
@@ -230,6 +259,7 @@
230 259
 			buildActionMask = 2147483647;
231 260
 			files = (
232 261
 				13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
262
+				19CA4076245DE96A00FEEC94 /* File.swift in Sources */,
233 263
 				13B07FC11A68108700A75B9A /* main.m in Sources */,
234 264
 			);
235 265
 			runOnlyForDeploymentPostprocessing = 0;
@@ -253,7 +283,9 @@
253 283
 			isa = XCBuildConfiguration;
254 284
 			baseConfigurationReference = 0A89B68A414A9ACE6081995A /* Pods-SafeAreaViewExample.debug.xcconfig */;
255 285
 			buildSettings = {
286
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
256 287
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
288
+				CLANG_ENABLE_MODULES = YES;
257 289
 				CURRENT_PROJECT_VERSION = 1;
258 290
 				DEAD_CODE_STRIPPING = NO;
259 291
 				INFOPLIST_FILE = SafeAreaViewExample/Info.plist;
@@ -265,6 +297,9 @@
265 297
 				);
266 298
 				PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
267 299
 				PRODUCT_NAME = SafeAreaViewExample;
300
+				SWIFT_OBJC_BRIDGING_HEADER = "SafeAreaViewExample-Bridging-Header.h";
301
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
302
+				SWIFT_VERSION = 5.0;
268 303
 				VERSIONING_SYSTEM = "apple-generic";
269 304
 			};
270 305
 			name = Debug;
@@ -273,7 +308,9 @@
273 308
 			isa = XCBuildConfiguration;
274 309
 			baseConfigurationReference = 69AAEDE94ED39E6A720417AA /* Pods-SafeAreaViewExample.release.xcconfig */;
275 310
 			buildSettings = {
311
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
276 312
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
313
+				CLANG_ENABLE_MODULES = YES;
277 314
 				CURRENT_PROJECT_VERSION = 1;
278 315
 				INFOPLIST_FILE = SafeAreaViewExample/Info.plist;
279 316
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -284,6 +321,8 @@
284 321
 				);
285 322
 				PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
286 323
 				PRODUCT_NAME = SafeAreaViewExample;
324
+				SWIFT_OBJC_BRIDGING_HEADER = "SafeAreaViewExample-Bridging-Header.h";
325
+				SWIFT_VERSION = 5.0;
287 326
 				VERSIONING_SYSTEM = "apple-generic";
288 327
 			};
289 328
 			name = Release;
@@ -291,6 +330,7 @@
291 330
 		83CBBA201A601CBA00E9B192 /* Debug */ = {
292 331
 			isa = XCBuildConfiguration;
293 332
 			buildSettings = {
333
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
294 334
 				ALWAYS_SEARCH_USER_PATHS = NO;
295 335
 				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
296 336
 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
@@ -318,6 +358,7 @@
318 358
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
319 359
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
320 360
 				COPY_PHASE_STRIP = NO;
361
+				ENABLE_BITCODE = NO;
321 362
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
322 363
 				ENABLE_TESTABILITY = YES;
323 364
 				GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -338,6 +379,7 @@
338 379
 				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
339 380
 				MTL_ENABLE_DEBUG_INFO = YES;
340 381
 				ONLY_ACTIVE_ARCH = YES;
382
+				OTHER_CFLAGS = "-DFB_SONARKIT_ENABLED=1";
341 383
 				SDKROOT = iphoneos;
342 384
 			};
343 385
 			name = Debug;
@@ -345,6 +387,7 @@
345 387
 		83CBBA211A601CBA00E9B192 /* Release */ = {
346 388
 			isa = XCBuildConfiguration;
347 389
 			buildSettings = {
390
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
348 391
 				ALWAYS_SEARCH_USER_PATHS = NO;
349 392
 				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
350 393
 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
@@ -372,6 +415,7 @@
372 415
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
373 416
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
374 417
 				COPY_PHASE_STRIP = YES;
418
+				ENABLE_BITCODE = NO;
375 419
 				ENABLE_NS_ASSERTIONS = NO;
376 420
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
377 421
 				GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -384,6 +428,7 @@
384 428
 				GCC_WARN_UNUSED_VARIABLE = YES;
385 429
 				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
386 430
 				MTL_ENABLE_DEBUG_INFO = NO;
431
+				OTHER_CFLAGS = "-DFB_SONARKIT_ENABLED=1";
387 432
 				SDKROOT = iphoneos;
388 433
 				VALIDATE_PRODUCT = YES;
389 434
 			};

+ 11
- 15
example/ios/SafeAreaViewExample.xcodeproj/xcshareddata/xcschemes/SafeAreaViewExample.xcscheme 查看文件

@@ -1,9 +1,9 @@
1 1
 <?xml version="1.0" encoding="UTF-8"?>
2 2
 <Scheme
3
-   LastUpgradeVersion = "1030"
3
+   LastUpgradeVersion = "1140"
4 4
    version = "1.3">
5 5
    <BuildAction
6
-      parallelizeBuildables = "NO"
6
+      parallelizeBuildables = "YES"
7 7
       buildImplicitDependencies = "YES">
8 8
       <BuildActionEntries>
9 9
          <BuildActionEntry
@@ -55,6 +55,15 @@
55 55
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
56 56
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
57 57
       shouldUseLaunchSchemeArgsEnv = "YES">
58
+      <MacroExpansion>
59
+         <BuildableReference
60
+            BuildableIdentifier = "primary"
61
+            BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
62
+            BuildableName = "SafeAreaViewExample.app"
63
+            BlueprintName = "SafeAreaViewExample"
64
+            ReferencedContainer = "container:SafeAreaViewExample.xcodeproj">
65
+         </BuildableReference>
66
+      </MacroExpansion>
58 67
       <Testables>
59 68
          <TestableReference
60 69
             skipped = "NO">
@@ -67,17 +76,6 @@
67 76
             </BuildableReference>
68 77
          </TestableReference>
69 78
       </Testables>
70
-      <MacroExpansion>
71
-         <BuildableReference
72
-            BuildableIdentifier = "primary"
73
-            BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
74
-            BuildableName = "SafeAreaViewExample.app"
75
-            BlueprintName = "SafeAreaViewExample"
76
-            ReferencedContainer = "container:SafeAreaViewExample.xcodeproj">
77
-         </BuildableReference>
78
-      </MacroExpansion>
79
-      <AdditionalOptions>
80
-      </AdditionalOptions>
81 79
    </TestAction>
82 80
    <LaunchAction
83 81
       buildConfiguration = "Debug"
@@ -99,8 +97,6 @@
99 97
             ReferencedContainer = "container:SafeAreaViewExample.xcodeproj">
100 98
          </BuildableReference>
101 99
       </BuildableProductRunnable>
102
-      <AdditionalOptions>
103
-      </AdditionalOptions>
104 100
    </LaunchAction>
105 101
    <ProfileAction
106 102
       buildConfiguration = "Release"

+ 0
- 7
example/ios/SafeAreaViewExample/AppDelegate.h 查看文件

@@ -1,10 +1,3 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8 1
 #import <React/RCTBridgeDelegate.h>
9 2
 #import <UIKit/UIKit.h>
10 3
 

+ 22
- 7
example/ios/SafeAreaViewExample/AppDelegate.m 查看文件

@@ -1,20 +1,35 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8 1
 #import "AppDelegate.h"
9 2
 
10 3
 #import <React/RCTBridge.h>
11 4
 #import <React/RCTBundleURLProvider.h>
12 5
 #import <React/RCTRootView.h>
13 6
 
7
+// #if DEBUG
8
+// #import <FlipperKit/FlipperClient.h>
9
+// #import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
10
+// #import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
11
+// #import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
12
+// #import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
13
+// #import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
14
+// static void InitializeFlipper(UIApplication *application) {
15
+//   FlipperClient *client = [FlipperClient sharedClient];
16
+//   SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
17
+//   [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
18
+//   [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
19
+//   [client addPlugin:[FlipperKitReactPlugin new]];
20
+//   [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
21
+//   [client start];
22
+// }
23
+// #endif
24
+
14 25
 @implementation AppDelegate
15 26
 
16 27
 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
17 28
 {
29
+// #if DEBUG
30
+//   InitializeFlipper(application);
31
+// #endif
32
+
18 33
   RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
19 34
   RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
20 35
                                                    moduleName:@"SafeAreaViewExample"

+ 9
- 0
example/ios/SafeAreaViewExample/File.swift 查看文件

@@ -0,0 +1,9 @@
1
+//
2
+//  File.swift
3
+//  SafeAreaViewExample
4
+//
5
+//  Created by Janic Duplessis on 2020-05-02.
6
+//  Copyright © 2020 Facebook. All rights reserved.
7
+//
8
+
9
+import Foundation

+ 0
- 7
example/ios/SafeAreaViewExample/main.m 查看文件

@@ -1,10 +1,3 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8 1
 #import <UIKit/UIKit.h>
9 2
 
10 3
 #import "AppDelegate.h"

+ 22
- 0
example/package.json 查看文件

@@ -0,0 +1,22 @@
1
+{
2
+  "name": "example",
3
+  "dependencies": {
4
+    "@react-native-community/async-storage": "^1.10.1",
5
+    "@react-native-community/masked-view": "^0.1.10",
6
+    "@react-navigation/native": "^5.3.2",
7
+    "@react-navigation/stack": "^5.3.6",
8
+    "@react-navigation/bottom-tabs": "^5.4.4",
9
+    "expo": "^37.0.8",
10
+    "react": "^16.13.1",
11
+    "react-dom": "^16.13.1",
12
+    "react-native": "^0.63.0-rc.0",
13
+    "react-native-web": "^0.12.2",
14
+    "react-navigation": "^4.3.9",
15
+    "react-navigation-stack": "^2.5.0",
16
+    "react-navigation-tabs": "^2.8.13",
17
+    "react-native-gesture-handler": "^1.6.1",
18
+    "react-native-screens": "^2.7.0",
19
+    "react-native-reanimated": "^1.8.0",
20
+    "react-native-safe-area-view": "^1.1.1"
21
+  }
22
+}

+ 83
- 0
example/src/App.tsx 查看文件

@@ -0,0 +1,83 @@
1
+import 'react-native-gesture-handler';
2
+import * as React from 'react';
3
+import { DevSettings, View, Text } from 'react-native';
4
+import { enableScreens } from 'react-native-screens';
5
+import AsyncStorage from '@react-native-community/async-storage';
6
+import ReactNavigation4Example from './ReactNavigation4Example';
7
+import ReactNavigation5Example from './ReactNavigation5Example';
8
+import SimpleExample from './SimpleExample';
9
+import NativeStackExample from './NativeStackExample';
10
+import ReactNativeSafeAreaView from './ReactNativeSafeAreaView';
11
+
12
+enableScreens();
13
+
14
+const STORAGE_KEY = 'rnsac-current-example';
15
+
16
+export default function App() {
17
+  const [currentExample, setCurrentExample] = React.useState<string | null>(
18
+    null,
19
+  );
20
+
21
+  React.useEffect(() => {
22
+    async function loadCurrentExample() {
23
+      const example = await AsyncStorage.getItem(STORAGE_KEY);
24
+      setCurrentExample(example ?? null);
25
+    }
26
+    loadCurrentExample();
27
+  }, []);
28
+
29
+  React.useEffect(() => {
30
+    async function saveCurrentExample() {
31
+      if (currentExample != null) {
32
+        await AsyncStorage.setItem(STORAGE_KEY, currentExample);
33
+      }
34
+    }
35
+    saveCurrentExample();
36
+  }, [currentExample]);
37
+
38
+  React.useEffect(() => {
39
+    DevSettings.addMenuItem('Show Simple Example', () => {
40
+      setCurrentExample('simple');
41
+    });
42
+    DevSettings.addMenuItem('Show React Navigation 4 Example', () => {
43
+      setCurrentExample('react-navigation-4');
44
+    });
45
+    DevSettings.addMenuItem('Show React Navigation 5 Example', () => {
46
+      setCurrentExample('react-navigation-5');
47
+    });
48
+    DevSettings.addMenuItem('Show Native Stack Example', () => {
49
+      setCurrentExample('native-stack');
50
+    });
51
+    DevSettings.addMenuItem('Show React Native Safe Area View Example', () => {
52
+      setCurrentExample('react-native-safe-area-view');
53
+    });
54
+  }, []);
55
+
56
+  switch (currentExample) {
57
+    case 'simple':
58
+      return <SimpleExample />;
59
+    case 'react-navigation-4':
60
+      return <ReactNavigation4Example />;
61
+    case 'react-navigation-5':
62
+      return <ReactNavigation5Example />;
63
+    case 'native-stack':
64
+      return <NativeStackExample />;
65
+    case 'react-native-safe-area-view':
66
+      return <ReactNativeSafeAreaView />;
67
+    default:
68
+      return (
69
+        <View
70
+          style={{
71
+            flex: 1,
72
+            alignItems: 'center',
73
+            justifyContent: 'center',
74
+            padding: 24,
75
+          }}
76
+        >
77
+          <Text style={{ textAlign: 'center', fontSize: 14 }}>
78
+            Open the dev menu to choose an example
79
+          </Text>
80
+        </View>
81
+      );
82
+  }
83
+}

+ 74
- 0
example/src/NativeStackExample.tsx 查看文件

@@ -0,0 +1,74 @@
1
+import * as React from 'react';
2
+import { Text, View, Button } from 'react-native';
3
+import { NavigationContainer } from '@react-navigation/native';
4
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
5
+import { createNativeStackNavigator } from 'react-native-screens/native-stack';
6
+import type { StackScreenProps } from '@react-navigation/stack';
7
+
8
+type Routes = {
9
+  Home: undefined;
10
+  Details: undefined;
11
+  Settings: undefined;
12
+};
13
+
14
+function HomeScreen({ navigation }: StackScreenProps<Routes, 'Home'>) {
15
+  return (
16
+    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
17
+      <Text>Home Screen</Text>
18
+      <Button
19
+        title="Go to Details"
20
+        onPress={() => navigation.navigate('Details')}
21
+      />
22
+    </View>
23
+  );
24
+}
25
+
26
+function SettingsScreen({ navigation }: StackScreenProps<Routes, 'Settings'>) {
27
+  return (
28
+    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
29
+      <Text>Settings Screen</Text>
30
+      <Button
31
+        title="Go to Details"
32
+        onPress={() => navigation.navigate('Details')}
33
+      />
34
+    </View>
35
+  );
36
+}
37
+
38
+const Tab = createBottomTabNavigator();
39
+
40
+function TabsScreen() {
41
+  return (
42
+    <Tab.Navigator>
43
+      <Tab.Screen name="Home" component={HomeScreen} />
44
+      <Tab.Screen name="Settings" component={SettingsScreen} />
45
+    </Tab.Navigator>
46
+  );
47
+}
48
+
49
+function DetailsScreen({ navigation }: StackScreenProps<Routes, 'Details'>) {
50
+  return (
51
+    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
52
+      <Text>Details Screen</Text>
53
+      <Button
54
+        title="Go to Details... again"
55
+        onPress={() => navigation.push('Details')}
56
+      />
57
+      <Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
58
+      <Button title="Go back" onPress={() => navigation.goBack()} />
59
+    </View>
60
+  );
61
+}
62
+
63
+const Stack = createNativeStackNavigator();
64
+
65
+export default function NativeStackExample() {
66
+  return (
67
+    <NavigationContainer>
68
+      <Stack.Navigator>
69
+        <Stack.Screen name="Tabs" component={TabsScreen} />
70
+        <Stack.Screen name="Details" component={DetailsScreen} />
71
+      </Stack.Navigator>
72
+    </NavigationContainer>
73
+  );
74
+}

+ 14
- 0
example/src/ReactNativeSafeAreaView.tsx 查看文件

@@ -0,0 +1,14 @@
1
+import * as React from 'react';
2
+import { View } from 'react-native';
3
+import { SafeAreaProvider } from 'react-native-safe-area-context';
4
+import SafeAreaView from 'react-native-safe-area-view';
5
+
6
+export default function ReactNativeSafeAreaView() {
7
+  return (
8
+    <SafeAreaProvider>
9
+      <SafeAreaView style={{ flex: 1, backgroundColor: 'red' }}>
10
+        <View style={{ flex: 1, backgroundColor: 'blue' }} />
11
+      </SafeAreaView>
12
+    </SafeAreaProvider>
13
+  );
14
+}

+ 76
- 0
example/src/ReactNavigation4Example.tsx 查看文件

@@ -0,0 +1,76 @@
1
+import * as React from 'react';
2
+import { View, Text, Button } from 'react-native';
3
+import { createAppContainer } from 'react-navigation';
4
+import { createBottomTabNavigator } from 'react-navigation-tabs';
5
+import {
6
+  createStackNavigator,
7
+  NavigationStackProp,
8
+} from 'react-navigation-stack';
9
+import { SafeAreaProvider } from 'react-native-safe-area-context';
10
+
11
+type NavigationScreenProps = {
12
+  navigation: NavigationStackProp<{}, {}>;
13
+};
14
+
15
+function HomeScreen({ navigation }: NavigationScreenProps) {
16
+  return (
17
+    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
18
+      <Text>Home Screen</Text>
19
+      <Button
20
+        title="Go to Details"
21
+        onPress={() => navigation.navigate('Details')}
22
+      />
23
+    </View>
24
+  );
25
+}
26
+
27
+function SettingsScreen({ navigation }: NavigationScreenProps) {
28
+  return (
29
+    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
30
+      <Text>Settings Screen</Text>
31
+      <Button
32
+        title="Go to Details"
33
+        onPress={() => navigation.navigate('Details')}
34
+      />
35
+    </View>
36
+  );
37
+}
38
+
39
+const TabNavigator = createBottomTabNavigator({
40
+  Home: HomeScreen,
41
+  Settings: SettingsScreen,
42
+});
43
+
44
+function DetailsScreen({ navigation }: NavigationScreenProps) {
45
+  return (
46
+    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
47
+      <Text>Details Screen</Text>
48
+      <Button
49
+        title="Go to Details... again"
50
+        onPress={() => navigation.push('Details')}
51
+      />
52
+      <Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
53
+      <Button title="Go back" onPress={() => navigation.goBack()} />
54
+    </View>
55
+  );
56
+}
57
+
58
+const AppNavigator = createStackNavigator(
59
+  {
60
+    Tabs: TabNavigator,
61
+    Details: DetailsScreen,
62
+  },
63
+  {
64
+    initialRouteName: 'Tabs',
65
+  },
66
+);
67
+
68
+const AppContainer = createAppContainer(AppNavigator);
69
+
70
+export default function ReactNavigation4Example() {
71
+  return (
72
+    <SafeAreaProvider>
73
+      <AppContainer />
74
+    </SafeAreaProvider>
75
+  );
76
+}

+ 76
- 0
example/src/ReactNavigation5Example.tsx 查看文件

@@ -0,0 +1,76 @@
1
+import * as React from 'react';
2
+import { Text, View, Button } from 'react-native';
3
+import { NavigationContainer } from '@react-navigation/native';
4
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
5
+import {
6
+  createStackNavigator,
7
+  StackScreenProps,
8
+} from '@react-navigation/stack';
9
+
10
+type Routes = {
11
+  Home: undefined;
12
+  Details: undefined;
13
+  Settings: undefined;
14
+};
15
+
16
+function HomeScreen({ navigation }: StackScreenProps<Routes, 'Home'>) {
17
+  return (
18
+    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
19
+      <Text>Home Screen</Text>
20
+      <Button
21
+        title="Go to Details"
22
+        onPress={() => navigation.navigate('Details')}
23
+      />
24
+    </View>
25
+  );
26
+}
27
+
28
+function SettingsScreen({ navigation }: StackScreenProps<Routes, 'Settings'>) {
29
+  return (
30
+    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
31
+      <Text>Settings Screen</Text>
32
+      <Button
33
+        title="Go to Details"
34
+        onPress={() => navigation.navigate('Details')}
35
+      />
36
+    </View>
37
+  );
38
+}
39
+
40
+const Tab = createBottomTabNavigator();
41
+
42
+function TabsScreen() {
43
+  return (
44
+    <Tab.Navigator>
45
+      <Tab.Screen name="Home" component={HomeScreen} />
46
+      <Tab.Screen name="Settings" component={SettingsScreen} />
47
+    </Tab.Navigator>
48
+  );
49
+}
50
+
51
+function DetailsScreen({ navigation }: StackScreenProps<Routes, 'Details'>) {
52
+  return (
53
+    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
54
+      <Text>Details Screen</Text>
55
+      <Button
56
+        title="Go to Details... again"
57
+        onPress={() => navigation.push('Details')}
58
+      />
59
+      <Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
60
+      <Button title="Go back" onPress={() => navigation.goBack()} />
61
+    </View>
62
+  );
63
+}
64
+
65
+const Stack = createStackNavigator();
66
+
67
+export default function ReactNavigation5Example() {
68
+  return (
69
+    <NavigationContainer>
70
+      <Stack.Navigator>
71
+        <Stack.Screen name="Tabs" component={TabsScreen} />
72
+        <Stack.Screen name="Details" component={DetailsScreen} />
73
+      </Stack.Navigator>
74
+    </NavigationContainer>
75
+  );
76
+}

+ 92
- 0
example/src/SimpleExample.tsx 查看文件

@@ -0,0 +1,92 @@
1
+import * as React from 'react';
2
+import { View, Text, StatusBar, ScrollView } from 'react-native';
3
+
4
+import {
5
+  SafeAreaProvider,
6
+  useSafeAreaInsets,
7
+  initialWindowMetrics,
8
+  useSafeAreaFrame,
9
+} from 'react-native-safe-area-context';
10
+
11
+const DataView = ({ data }: { data: object | null | undefined }) => (
12
+  <Text style={{ fontSize: 16, lineHeight: 24, color: '#292929' }}>
13
+    {data == null
14
+      ? 'null'
15
+      : Object.entries(data)
16
+          .map(([key, value]) => `${key}: ${value}`)
17
+          .join('\n')}
18
+  </Text>
19
+);
20
+
21
+const Card = ({
22
+  title,
23
+  children,
24
+}: {
25
+  title: string;
26
+  children: React.ReactNode;
27
+}) => (
28
+  <View style={{ padding: 16, backgroundColor: 'white', marginBottom: 4 }}>
29
+    <Text
30
+      style={{
31
+        fontSize: 20,
32
+        fontWeight: 'bold',
33
+        marginBottom: 16,
34
+        color: '#292929',
35
+      }}
36
+    >
37
+      {title}
38
+    </Text>
39
+    {children}
40
+  </View>
41
+);
42
+
43
+const BORDER_WIDTH = 8;
44
+
45
+function SimpleExampleScreen() {
46
+  const insets = useSafeAreaInsets();
47
+  const frame = useSafeAreaFrame();
48
+
49
+  return (
50
+    <>
51
+      <StatusBar barStyle="dark-content" backgroundColor="transparent" />
52
+      <View
53
+        style={{
54
+          width: frame.width,
55
+          height: frame.height,
56
+          backgroundColor: 'red',
57
+          paddingTop: insets.top - BORDER_WIDTH,
58
+          paddingLeft: insets.left - BORDER_WIDTH,
59
+          paddingBottom: insets.bottom - BORDER_WIDTH,
60
+          paddingRight: insets.right - BORDER_WIDTH,
61
+          borderColor: 'blue',
62
+          borderWidth: BORDER_WIDTH,
63
+        }}
64
+      >
65
+        <ScrollView style={{ flex: 1, backgroundColor: '#eee' }}>
66
+          <Card title="Provider insets">
67
+            <DataView data={insets} />
68
+          </Card>
69
+          <Card title="Provider frame">
70
+            <DataView data={frame} />
71
+          </Card>
72
+          <Card title="Initial window insets">
73
+            <DataView data={initialWindowMetrics?.insets} />
74
+          </Card>
75
+          <Card title="Initial window frame">
76
+            <DataView data={initialWindowMetrics?.frame} />
77
+          </Card>
78
+        </ScrollView>
79
+      </View>
80
+    </>
81
+  );
82
+}
83
+
84
+export default function SimpleExample() {
85
+  return (
86
+    <View style={{ marginTop: 0, flex: 1 }}>
87
+      <SafeAreaProvider>
88
+        <SimpleExampleScreen />
89
+      </SafeAreaProvider>
90
+    </View>
91
+  );
92
+}

+ 15
- 2
ios/SafeAreaView/RNCSafeAreaView.m 查看文件

@@ -16,6 +16,7 @@ static BOOL UIEdgeInsetsEqualToEdgeInsetsWithThreshold(UIEdgeInsets insets1, UIE
16 16
 @implementation RNCSafeAreaView
17 17
 {
18 18
   UIEdgeInsets _currentSafeAreaInsets;
19
+  CGRect _currentFrame;
19 20
   BOOL _initialInsetsSent;
20 21
 }
21 22
 
@@ -75,13 +76,19 @@ static BOOL UIEdgeInsetsEqualToEdgeInsetsWithThreshold(UIEdgeInsets insets1, UIE
75 76
   }
76 77
 
77 78
   UIEdgeInsets safeAreaInsets = [self realOrEmulateSafeAreaInsets];
79
+  CGRect frame = [self convertRect:self.bounds toView:nil];
78 80
 
79
-  if (_initialInsetsSent && UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale())) {
81
+  if (
82
+    _initialInsetsSent &&
83
+    UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale()) &&
84
+    CGRectEqualToRect(frame, _currentFrame)
85
+  ) {
80 86
     return;
81 87
   }
82 88
 
83 89
   _initialInsetsSent = YES;
84 90
   _currentSafeAreaInsets = safeAreaInsets;
91
+  _currentFrame = frame;
85 92
 
86 93
   self.onInsetsChange(@{
87 94
     @"insets": @{
@@ -89,7 +96,13 @@ static BOOL UIEdgeInsetsEqualToEdgeInsetsWithThreshold(UIEdgeInsets insets1, UIE
89 96
       @"right": @(safeAreaInsets.right),
90 97
       @"bottom": @(safeAreaInsets.bottom),
91 98
       @"left": @(safeAreaInsets.left),
92
-    }
99
+    },
100
+    @"frame": @{
101
+      @"x": @(frame.origin.x),
102
+      @"y": @(frame.origin.y),
103
+      @"width": @(frame.size.width),
104
+      @"height": @(frame.size.height),
105
+    },
93 106
   });
94 107
 }
95 108
 

+ 13
- 5
ios/SafeAreaView/RNCSafeAreaViewManager.m 查看文件

@@ -24,11 +24,19 @@ RCT_EXPORT_VIEW_PROPERTY(onInsetsChange, RCTBubblingEventBlock)
24 24
     UIWindow* window = [[UIApplication sharedApplication] keyWindow];
25 25
     UIEdgeInsets safeAreaInsets = window.safeAreaInsets;
26 26
     return @{
27
-      @"initialWindowSafeAreaInsets": @{
28
-        @"top": @(safeAreaInsets.top),
29
-        @"right": @(safeAreaInsets.right),
30
-        @"bottom": @(safeAreaInsets.bottom),
31
-        @"left": @(safeAreaInsets.left),
27
+      @"initialWindowMetrics": @{
28
+        @"insets": @{
29
+          @"top": @(safeAreaInsets.top),
30
+          @"right": @(safeAreaInsets.right),
31
+          @"bottom": @(safeAreaInsets.bottom),
32
+          @"left": @(safeAreaInsets.left),
33
+        },
34
+        @"frame": @{
35
+          @"x": @(window.frame.origin.x),
36
+          @"y": @(window.frame.origin.y),
37
+          @"width": @(window.frame.size.width),
38
+          @"height": @(window.frame.size.height),
39
+        },
32 40
       }
33 41
     };
34 42
   } else {

+ 0
- 17
metro.config.js 查看文件

@@ -1,17 +0,0 @@
1
-/**
2
- * Metro configuration for React Native
3
- * https://github.com/facebook/react-native
4
- *
5
- * @format
6
- */
7
-
8
-module.exports = {
9
-  transformer: {
10
-    getTransformOptions: async () => ({
11
-      transform: {
12
-        experimentalImportSupport: false,
13
-        inlineRequires: false,
14
-      },
15
-    }),
16
-  },
17
-};

+ 39
- 21
package.json 查看文件

@@ -1,6 +1,6 @@
1 1
 {
2 2
   "name": "react-native-safe-area-context",
3
-  "version": "0.7.3",
3
+  "version": "1.0.2",
4 4
   "description": "A flexible way to handle safe area, also works on Android and web.",
5 5
   "main": "lib/commonjs/index.js",
6 6
   "module": "lib/module/index.js",
@@ -27,7 +27,10 @@
27 27
     "validate:typescript": "tsc --project ./ --noEmit",
28 28
     "validate:prettier": "prettier \"src/**/*.{js,ts,tsx}\" \"example/**/*.{js,ts,tsx}\" --check",
29 29
     "validate:jest": "jest",
30
-    "prepare": "bob build"
30
+    "prepare": "bob build",
31
+    "example:ios": "cd ./example && react-native run-ios",
32
+    "example:android": "cd ./example && react-native run-android --no-jetifier",
33
+    "example:expo": "expo start --config example/app.json"
31 34
   },
32 35
   "keywords": [
33 36
     "react-native",
@@ -43,27 +46,42 @@
43 46
   },
44 47
   "dependencies": {},
45 48
   "devDependencies": {
46
-    "@react-native-community/bob": "^0.8.0",
47
-    "@react-native-community/eslint-config": "^0.0.7",
48
-    "@types/jest": "^25.1.1",
49
-    "@types/react": "^16.9.19",
50
-    "@types/react-native": "^0.61.10",
49
+    "@react-native-community/async-storage": "^1.10.1",
50
+    "@react-native-community/bob": "^0.10.1",
51
+    "@react-native-community/eslint-config": "^1.1.0",
52
+    "@react-native-community/masked-view": "^0.1.10",
53
+    "@react-navigation/native": "^5.3.2",
54
+    "@react-navigation/stack": "^5.3.6",
55
+    "@react-navigation/bottom-tabs": "^5.4.4",
56
+    "@types/jest": "^25.2.1",
57
+    "@types/react": "^16.9.34",
58
+    "@types/react-native": "^0.62.5",
59
+    "@types/react-dom": "^16.9.7",
51 60
     "@types/react-test-renderer": "^16.9.2",
52
-    "@typescript-eslint/eslint-plugin": "^2.19.0",
53
-    "@typescript-eslint/parser": "^2.19.0",
61
+    "@typescript-eslint/eslint-plugin": "^2.30.0",
62
+    "@typescript-eslint/parser": "^2.30.0",
63
+    "babel-plugin-module-resolver": "^4.0.0",
54 64
     "eslint": "6.8.0",
55
-    "eslint-config-prettier": "^6.10.0",
56
-    "eslint-plugin-prettier": "3.1.2",
57
-    "expo": "^36.0.2",
58
-    "jest": "^25.1.0",
59
-    "metro-react-native-babel-preset": "^0.58.0",
60
-    "prettier": "^1.19.1",
61
-    "react": "^16.11.0",
62
-    "react-dom": "^16.12.0",
63
-    "react-native": "^0.61.0",
64
-    "react-native-web": "^0.12.0",
65
-    "react-test-renderer": "^16.12.0",
66
-    "typescript": "^3.7.5"
65
+    "eslint-config-prettier": "^6.11.0",
66
+    "eslint-plugin-prettier": "3.1.3",
67
+    "expo": "^37.0.8",
68
+    "expo-cli": "^3.20.1",
69
+    "jest": "^25.5.4",
70
+    "metro-react-native-babel-preset": "^0.59.0",
71
+    "prettier": "^2.0.5",
72
+    "react": "^16.13.1",
73
+    "react-dom": "^16.13.1",
74
+    "react-native": "^0.63.0-rc.0",
75
+    "react-native-web": "^0.12.2",
76
+    "react-navigation": "^4.3.9",
77
+    "react-navigation-stack": "^2.5.0",
78
+    "react-navigation-tabs": "^2.8.13",
79
+    "react-native-safe-area-view": "1.1.1",
80
+    "react-native-gesture-handler": "^1.6.1",
81
+    "react-native-screens": "^2.7.0",
82
+    "react-native-reanimated": "^1.8.0",
83
+    "react-test-renderer": "^16.13.1",
84
+    "typescript": "^3.8.3"
67 85
   },
68 86
   "repository": {
69 87
     "type": "git",

+ 17
- 0
src/InitialWindow.native.ts 查看文件

@@ -0,0 +1,17 @@
1
+import { UIManager } from 'react-native';
2
+import { Metrics } from './SafeArea.types';
3
+
4
+const RNCSafeAreaViewConfig = UIManager.getViewManagerConfig(
5
+  'RNCSafeAreaView',
6
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+) as any;
8
+
9
+export const initialWindowMetrics = (RNCSafeAreaViewConfig != null &&
10
+RNCSafeAreaViewConfig.Constants != null
11
+  ? RNCSafeAreaViewConfig.Constants.initialWindowMetrics
12
+  : null) as Metrics | null;
13
+
14
+/**
15
+ * @deprecated
16
+ */
17
+export const initialWindowSafeAreaInsets = initialWindowMetrics?.insets;

+ 8
- 0
src/InitialWindow.ts 查看文件

@@ -0,0 +1,8 @@
1
+import { EdgeInsets, Metrics } from './SafeArea.types';
2
+
3
+export const initialWindowMetrics: Metrics | null = null;
4
+
5
+/**
6
+ * @deprecated
7
+ */
8
+export const initialWindowSafeAreaInsets: EdgeInsets | null = null;

+ 0
- 12
src/InitialWindowSafeAreaInsets.ts 查看文件

@@ -1,12 +0,0 @@
1
-import { UIManager } from 'react-native';
2
-import { EdgeInsets } from './SafeArea.types';
3
-
4
-const RNCSafeAreaViewConfig = UIManager.getViewManagerConfig(
5
-  'RNCSafeAreaView',
6
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
-) as any;
8
-
9
-export default (RNCSafeAreaViewConfig != null &&
10
-RNCSafeAreaViewConfig.Constants != null
11
-  ? RNCSafeAreaViewConfig.Constants.initialWindowSafeAreaInsets
12
-  : null) as EdgeInsets | null;

+ 0
- 4
src/InitialWindowSafeAreaInsets.web.ts 查看文件

@@ -1,4 +0,0 @@
1
-import { EdgeInsets } from './SafeArea.types';
2
-
3
-const initialWindowSafeAreaInsets: EdgeInsets | null = null;
4
-export default initialWindowSafeAreaInsets;

+ 6
- 0
src/NativeSafeAreaView.native.tsx 查看文件

@@ -0,0 +1,6 @@
1
+import { requireNativeComponent } from 'react-native';
2
+import { NativeSafeAreaViewProps } from './SafeArea.types';
3
+
4
+export default requireNativeComponent<NativeSafeAreaViewProps>(
5
+  'RNCSafeAreaView',
6
+);

+ 128
- 2
src/NativeSafeAreaView.tsx 查看文件

@@ -1,3 +1,129 @@
1
-import { requireNativeComponent } from 'react-native';
1
+import * as React from 'react';
2
+import { View } from 'react-native';
3
+import { NativeSafeAreaViewProps } from './SafeArea.types';
2 4
 
3
-export default requireNativeComponent('RNCSafeAreaView');
5
+/**
6
+ * TODO:
7
+ * Currently insets and frame are based on the window and are not
8
+ * relative to the provider view. This is inconsistent with iOS and Android.
9
+ * However in most cases if the provider view covers the screen this is not
10
+ * an issue.
11
+ */
12
+
13
+const CSSTransitions: Record<string, string> = {
14
+  WebkitTransition: 'webkitTransitionEnd',
15
+  Transition: 'transitionEnd',
16
+  MozTransition: 'transitionend',
17
+  MSTransition: 'msTransitionEnd',
18
+  OTransition: 'oTransitionEnd',
19
+};
20
+
21
+export default function NativeSafeAreaView({
22
+  children,
23
+  style,
24
+  onInsetsChange,
25
+}: NativeSafeAreaViewProps) {
26
+  React.useEffect(() => {
27
+    // Skip for SSR.
28
+    if (typeof document === 'undefined') {
29
+      return;
30
+    }
31
+
32
+    const element = createContextElement();
33
+    document.body.appendChild(element);
34
+    const onEnd = () => {
35
+      const {
36
+        paddingTop,
37
+        paddingBottom,
38
+        paddingLeft,
39
+        paddingRight,
40
+      } = window.getComputedStyle(element);
41
+
42
+      const insets = {
43
+        top: paddingTop ? parseInt(paddingTop, 10) : 0,
44
+        bottom: paddingBottom ? parseInt(paddingBottom, 10) : 0,
45
+        left: paddingLeft ? parseInt(paddingLeft, 10) : 0,
46
+        right: paddingRight ? parseInt(paddingRight, 10) : 0,
47
+      };
48
+      const frame = {
49
+        x: 0,
50
+        y: 0,
51
+        width: document.documentElement.offsetWidth,
52
+        height: document.documentElement.offsetHeight,
53
+      };
54
+      // @ts-ignore: missing properties
55
+      onInsetsChange({ nativeEvent: { insets, frame } });
56
+    };
57
+    element.addEventListener(getSupportedTransitionEvent(), onEnd);
58
+    onEnd();
59
+    return () => {
60
+      document.body.removeChild(element);
61
+      element.removeEventListener(getSupportedTransitionEvent(), onEnd);
62
+    };
63
+  }, [onInsetsChange]);
64
+
65
+  return <View style={style}>{children}</View>;
66
+}
67
+
68
+let _supportedTransitionEvent: string | null = null;
69
+function getSupportedTransitionEvent(): string {
70
+  if (_supportedTransitionEvent !== null) {
71
+    return _supportedTransitionEvent;
72
+  }
73
+  const element = document.createElement('invalidtype');
74
+
75
+  _supportedTransitionEvent = CSSTransitions.Transition;
76
+  for (const key in CSSTransitions) {
77
+    if (element.style[key as keyof CSSStyleDeclaration] !== undefined) {
78
+      _supportedTransitionEvent = CSSTransitions[key];
79
+      break;
80
+    }
81
+  }
82
+  return _supportedTransitionEvent;
83
+}
84
+
85
+type CssEnv = 'constant' | 'env';
86
+
87
+let _supportedEnv: CssEnv | null = null;
88
+function getSupportedEnv(): CssEnv {
89
+  if (_supportedEnv !== null) {
90
+    return _supportedEnv;
91
+  }
92
+  const { CSS } = window;
93
+  if (
94
+    CSS &&
95
+    CSS.supports &&
96
+    CSS.supports('top: constant(safe-area-inset-top)')
97
+  ) {
98
+    _supportedEnv = 'constant';
99
+  } else {
100
+    _supportedEnv = 'env';
101
+  }
102
+  return _supportedEnv;
103
+}
104
+
105
+function getInset(side: string): string {
106
+  return `${getSupportedEnv()}(safe-area-inset-${side})`;
107
+}
108
+
109
+function createContextElement(): HTMLElement {
110
+  const element = document.createElement('div');
111
+  const { style } = element;
112
+  style.position = 'fixed';
113
+  style.left = '0';
114
+  style.top = '0';
115
+  style.width = '0';
116
+  style.height = '0';
117
+  style.zIndex = '-1';
118
+  style.overflow = 'hidden';
119
+  style.visibility = 'hidden';
120
+  // Bacon: Anything faster than this and the callback will be invoked too early with the wrong insets
121
+  style.transitionDuration = '0.05s';
122
+  style.transitionProperty = 'padding';
123
+  style.transitionDelay = '0s';
124
+  style.paddingTop = getInset('top');
125
+  style.paddingBottom = getInset('bottom');
126
+  style.paddingLeft = getInset('left');
127
+  style.paddingRight = getInset('right');
128
+  return element;
129
+}

+ 0
- 122
src/NativeSafeAreaView.web.tsx 查看文件

@@ -1,122 +0,0 @@
1
-import * as React from 'react';
2
-import { ViewStyle, View } from 'react-native';
3
-
4
-import { InsetChangeNativeCallback } from './SafeArea.types';
5
-
6
-interface NativeSafeAreaViewProps {
7
-  children?: React.ReactNode;
8
-  style: ViewStyle;
9
-  onInsetsChange: InsetChangeNativeCallback;
10
-}
11
-
12
-const CSSTransitions: Record<string, string> = {
13
-  WebkitTransition: 'webkitTransitionEnd',
14
-  Transition: 'transitionEnd',
15
-  MozTransition: 'transitionend',
16
-  MSTransition: 'msTransitionEnd',
17
-  OTransition: 'oTransitionEnd',
18
-};
19
-
20
-export default function NativeSafeAreaView({
21
-  children,
22
-  style,
23
-  onInsetsChange,
24
-}: NativeSafeAreaViewProps) {
25
-  React.useEffect(() => {
26
-    // Skip for SSR.
27
-    if (typeof document === 'undefined') {
28
-      return;
29
-    }
30
-
31
-    const element = createContextElement();
32
-    document.body.appendChild(element);
33
-    const onEnd = () => {
34
-      const {
35
-        paddingTop,
36
-        paddingBottom,
37
-        paddingLeft,
38
-        paddingRight,
39
-      } = window.getComputedStyle(element);
40
-
41
-      const insets = {
42
-        top: paddingTop ? parseInt(paddingTop, 10) : 0,
43
-        bottom: paddingBottom ? parseInt(paddingBottom, 10) : 0,
44
-        left: paddingLeft ? parseInt(paddingLeft, 10) : 0,
45
-        right: paddingRight ? parseInt(paddingRight, 10) : 0,
46
-      };
47
-      // @ts-ignore: missing properties
48
-      onInsetsChange({ nativeEvent: { insets } });
49
-    };
50
-    element.addEventListener(getSupportedTransitionEvent(), onEnd);
51
-    onEnd();
52
-    return () => {
53
-      document.body.removeChild(element);
54
-      element.removeEventListener(getSupportedTransitionEvent(), onEnd);
55
-    };
56
-  }, [onInsetsChange]);
57
-
58
-  return <View style={style}>{children}</View>;
59
-}
60
-
61
-let _supportedTransitionEvent: string | null = null;
62
-function getSupportedTransitionEvent(): string {
63
-  if (_supportedTransitionEvent !== null) {
64
-    return _supportedTransitionEvent;
65
-  }
66
-  const element = document.createElement('invalidtype');
67
-
68
-  _supportedTransitionEvent = CSSTransitions.Transition;
69
-  for (const key in CSSTransitions) {
70
-    if (element.style[key as keyof CSSStyleDeclaration] !== undefined) {
71
-      _supportedTransitionEvent = CSSTransitions[key];
72
-      break;
73
-    }
74
-  }
75
-  return _supportedTransitionEvent;
76
-}
77
-
78
-type CssEnv = 'constant' | 'env';
79
-
80
-let _supportedEnv: CssEnv | null = null;
81
-function getSupportedEnv(): CssEnv {
82
-  if (_supportedEnv !== null) {
83
-    return _supportedEnv;
84
-  }
85
-  const { CSS } = window;
86
-  if (
87
-    CSS &&
88
-    CSS.supports &&
89
-    CSS.supports('top: constant(safe-area-inset-top)')
90
-  ) {
91
-    _supportedEnv = 'constant';
92
-  } else {
93
-    _supportedEnv = 'env';
94
-  }
95
-  return _supportedEnv;
96
-}
97
-
98
-function getInset(side: string): string {
99
-  return `${getSupportedEnv()}(safe-area-inset-${side})`;
100
-}
101
-
102
-function createContextElement(): HTMLElement {
103
-  const element = document.createElement('div');
104
-  const { style } = element;
105
-  style.position = 'fixed';
106
-  style.left = '0';
107
-  style.top = '0';
108
-  style.width = '0';
109
-  style.height = '0';
110
-  style.zIndex = '-1';
111
-  style.overflow = 'hidden';
112
-  style.visibility = 'hidden';
113
-  // Bacon: Anything faster than this and the callback will be invoked too early with the wrong insets
114
-  style.transitionDuration = '0.05s';
115
-  style.transitionProperty = 'padding';
116
-  style.transitionDelay = '0s';
117
-  style.paddingTop = getInset('top');
118
-  style.paddingBottom = getInset('bottom');
119
-  style.paddingLeft = getInset('left');
120
-  style.paddingRight = getInset('right');
121
-  return element;
122
-}

+ 20
- 2
src/SafeArea.types.ts 查看文件

@@ -1,4 +1,4 @@
1
-import { NativeSyntheticEvent } from 'react-native';
1
+import { NativeSyntheticEvent, ViewStyle } from 'react-native';
2 2
 
3 3
 export interface EdgeInsets {
4 4
   top: number;
@@ -7,6 +7,24 @@ export interface EdgeInsets {
7 7
   left: number;
8 8
 }
9 9
 
10
-export type InsetChangedEvent = NativeSyntheticEvent<{ insets: EdgeInsets }>;
10
+export interface Rect {
11
+  x: number;
12
+  y: number;
13
+  width: number;
14
+  height: number;
15
+}
16
+
17
+export interface Metrics {
18
+  insets: EdgeInsets;
19
+  frame: Rect;
20
+}
21
+
22
+export type InsetChangedEvent = NativeSyntheticEvent<Metrics>;
11 23
 
12 24
 export type InsetChangeNativeCallback = (event: InsetChangedEvent) => void;
25
+
26
+export interface NativeSafeAreaViewProps {
27
+  children?: React.ReactNode;
28
+  style?: ViewStyle;
29
+  onInsetsChange: InsetChangeNativeCallback;
30
+}

+ 123
- 0
src/SafeAreaContext.tsx 查看文件

@@ -0,0 +1,123 @@
1
+import * as React from 'react';
2
+import { StyleSheet, Dimensions } from 'react-native';
3
+import NativeSafeAreaView from './NativeSafeAreaView';
4
+import { EdgeInsets, InsetChangedEvent, Metrics, Rect } from './SafeArea.types';
5
+
6
+export const SafeAreaInsetsContext = React.createContext<EdgeInsets | null>(
7
+  null,
8
+);
9
+
10
+export const SafeAreaFrameContext = React.createContext<Rect | null>(null);
11
+
12
+export interface SafeAreaViewProps {
13
+  children?: React.ReactNode;
14
+  initialMetrics?: Metrics | null;
15
+  /**
16
+   * @deprecated
17
+   */
18
+  initialSafeAreaInsets?: EdgeInsets | null;
19
+}
20
+
21
+export function SafeAreaProvider({
22
+  children,
23
+  initialMetrics,
24
+  initialSafeAreaInsets,
25
+}: SafeAreaViewProps) {
26
+  const parentInsets = useParentSafeAreaInsets();
27
+  const parentFrame = useParentSafeAreaFrame();
28
+  const [insets, setInsets] = React.useState<EdgeInsets | null>(
29
+    initialMetrics?.insets ?? initialSafeAreaInsets ?? parentInsets ?? null,
30
+  );
31
+  const [frame, setFrame] = React.useState<Rect>(
32
+    initialMetrics?.frame ??
33
+      parentFrame ?? {
34
+        // Backwards compat so we render anyway if we don't have frame.
35
+        x: 0,
36
+        y: 0,
37
+        width: Dimensions.get('window').width,
38
+        height: Dimensions.get('window').height,
39
+      },
40
+  );
41
+  const onInsetsChange = React.useCallback((event: InsetChangedEvent) => {
42
+    // Backwards compat with old native code that won't send frame.
43
+    if (event.nativeEvent.frame != null) {
44
+      setFrame(event.nativeEvent.frame);
45
+    }
46
+    setInsets(event.nativeEvent.insets);
47
+  }, []);
48
+
49
+  return (
50
+    <NativeSafeAreaView style={styles.fill} onInsetsChange={onInsetsChange}>
51
+      {insets != null ? (
52
+        <SafeAreaFrameContext.Provider value={frame}>
53
+          <SafeAreaInsetsContext.Provider value={insets}>
54
+            {children}
55
+          </SafeAreaInsetsContext.Provider>
56
+        </SafeAreaFrameContext.Provider>
57
+      ) : null}
58
+    </NativeSafeAreaView>
59
+  );
60
+}
61
+
62
+const styles = StyleSheet.create({
63
+  fill: { flex: 1 },
64
+});
65
+
66
+function useParentSafeAreaInsets(): EdgeInsets | null {
67
+  return React.useContext(SafeAreaInsetsContext);
68
+}
69
+
70
+function useParentSafeAreaFrame(): Rect | null {
71
+  return React.useContext(SafeAreaFrameContext);
72
+}
73
+
74
+export function useSafeAreaInsets(): EdgeInsets {
75
+  const safeArea = React.useContext(SafeAreaInsetsContext);
76
+  if (safeArea == null) {
77
+    throw new Error(
78
+      'No safe area insets value available. Make sure you are rendering `<SafeAreaProvider>` at the top of your app.',
79
+    );
80
+  }
81
+  return safeArea;
82
+}
83
+
84
+export function useSafeAreaFrame(): Rect {
85
+  const frame = React.useContext(SafeAreaFrameContext);
86
+  if (frame == null) {
87
+    throw new Error(
88
+      'No safe area frame value available. Make sure you are rendering `<SafeAreaProvider>` at the top of your app.',
89
+    );
90
+  }
91
+  return frame;
92
+}
93
+
94
+export function withSafeAreaInsets<T>(
95
+  WrappedComponent: React.ComponentType<T>,
96
+) {
97
+  return (props: T) => (
98
+    <SafeAreaConsumer>
99
+      {(insets) => <WrappedComponent {...props} insets={insets} />}
100
+    </SafeAreaConsumer>
101
+  );
102
+}
103
+
104
+/**
105
+ * @deprecated
106
+ */
107
+export function useSafeArea(): EdgeInsets {
108
+  return useSafeAreaInsets();
109
+}
110
+
111
+/**
112
+ * @deprecated
113
+ */
114
+export function SafeAreaConsumer(
115
+  props: React.ComponentProps<typeof SafeAreaInsetsContext.Consumer>,
116
+) {
117
+  return <SafeAreaInsetsContext.Consumer {...props} />;
118
+}
119
+
120
+/**
121
+ * @deprecated
122
+ */
123
+export const SafeAreaContext = SafeAreaInsetsContext;

+ 25
- 0
src/SafeAreaView.tsx 查看文件

@@ -0,0 +1,25 @@
1
+import * as React from 'react';
2
+import { View, ViewProps } from 'react-native';
3
+import { useSafeAreaInsets } from './SafeAreaContext';
4
+
5
+export function SafeAreaView({
6
+  style,
7
+  ...rest
8
+}: ViewProps & { children: React.ReactNode }) {
9
+  const insets = useSafeAreaInsets();
10
+
11
+  return (
12
+    <View
13
+      style={[
14
+        {
15
+          paddingTop: insets.top,
16
+          paddingRight: insets.right,
17
+          paddingBottom: insets.bottom,
18
+          paddingLeft: insets.left,
19
+        },
20
+        style,
21
+      ]}
22
+      {...rest}
23
+    />
24
+  );
25
+}

+ 121
- 0
src/__tests__/SafeAreaContext-test.tsx 查看文件

@@ -0,0 +1,121 @@
1
+import * as React from 'react';
2
+import { View } from 'react-native';
3
+import * as ReactTestRenderer from 'react-test-renderer';
4
+import NativeSafeAreaView from '../NativeSafeAreaView';
5
+import {
6
+  SafeAreaProvider,
7
+  useSafeAreaInsets,
8
+  useSafeAreaFrame,
9
+} from '../SafeAreaContext';
10
+import { Metrics } from '../SafeArea.types';
11
+
12
+const TEST_METRICS_1: Metrics = {
13
+  insets: { top: 1, left: 2, right: 3, bottom: 4 },
14
+  frame: { x: 0, y: 0, height: 100, width: 100 },
15
+};
16
+const TEST_METRICS_2: Metrics = {
17
+  insets: { top: 2, left: 3, right: 4, bottom: 5 },
18
+  frame: { x: 0, y: 0, width: 10, height: 16 },
19
+};
20
+
21
+const PrintInsetsTestView = () => {
22
+  const insets = useSafeAreaInsets();
23
+  const frame = useSafeAreaFrame();
24
+  return (
25
+    <View
26
+      style={{
27
+        paddingTop: insets.top,
28
+        paddingLeft: insets.left,
29
+        paddingBottom: insets.bottom,
30
+        paddingRight: insets.right,
31
+        top: frame.y,
32
+        left: frame.y,
33
+        width: frame.width,
34
+        height: frame.height,
35
+      }}
36
+    />
37
+  );
38
+};
39
+
40
+describe('SafeAreaProvider', () => {
41
+  it('renders', () => {
42
+    const component = ReactTestRenderer.create(<SafeAreaProvider />);
43
+    expect(component).toMatchSnapshot();
44
+  });
45
+
46
+  it('does not render child until inset values are received', () => {
47
+    const component = ReactTestRenderer.create(
48
+      <SafeAreaProvider>
49
+        <PrintInsetsTestView />
50
+      </SafeAreaProvider>,
51
+    );
52
+    expect(component).toMatchSnapshot();
53
+  });
54
+
55
+  it('renders child when inset values are received', () => {
56
+    const component = ReactTestRenderer.create(
57
+      <SafeAreaProvider>
58
+        <PrintInsetsTestView />
59
+      </SafeAreaProvider>,
60
+    );
61
+    expect(component).toMatchSnapshot();
62
+    const { onInsetsChange } = component.root.findByType(
63
+      NativeSafeAreaView,
64
+    ).props;
65
+    ReactTestRenderer.act(() => {
66
+      onInsetsChange({
67
+        nativeEvent: TEST_METRICS_1,
68
+      });
69
+    });
70
+    expect(component).toMatchSnapshot();
71
+  });
72
+
73
+  it('supports setting initial insets', () => {
74
+    const component = ReactTestRenderer.create(
75
+      <SafeAreaProvider initialMetrics={TEST_METRICS_1}>
76
+        <PrintInsetsTestView />
77
+      </SafeAreaProvider>,
78
+    );
79
+    expect(component).toMatchSnapshot();
80
+  });
81
+
82
+  it('uses parent insets when available', () => {
83
+    const component = ReactTestRenderer.create(
84
+      <SafeAreaProvider initialMetrics={TEST_METRICS_1}>
85
+        <SafeAreaProvider>
86
+          <PrintInsetsTestView />
87
+        </SafeAreaProvider>
88
+      </SafeAreaProvider>,
89
+    );
90
+    expect(component).toMatchSnapshot();
91
+  });
92
+
93
+  it('uses inner insets', () => {
94
+    const component = ReactTestRenderer.create(
95
+      <SafeAreaProvider initialMetrics={TEST_METRICS_1}>
96
+        <SafeAreaProvider initialMetrics={TEST_METRICS_2}>
97
+          <PrintInsetsTestView />
98
+        </SafeAreaProvider>
99
+      </SafeAreaProvider>,
100
+    );
101
+    expect(component).toMatchSnapshot();
102
+  });
103
+
104
+  it('throws when no provider is rendered', () => {
105
+    // Silence the React error boundary warning; we expect an uncaught error.
106
+    const consoleErrorMock = jest
107
+      .spyOn(console, 'error')
108
+      .mockImplementation((message) => {
109
+        if (message.startsWith('The above error occured in the ')) {
110
+          return;
111
+        }
112
+      });
113
+    expect(() => {
114
+      ReactTestRenderer.create(<PrintInsetsTestView />);
115
+    }).toThrow(
116
+      'No safe area insets value available. Make sure you are rendering `<SafeAreaProvider>` at the top of your app.',
117
+    );
118
+
119
+    consoleErrorMock.mockRestore();
120
+  });
121
+});

+ 35
- 0
src/__tests__/SafeAreaView-test.tsx 查看文件

@@ -0,0 +1,35 @@
1
+import * as React from 'react';
2
+import { View } from 'react-native';
3
+import * as ReactTestRenderer from 'react-test-renderer';
4
+import { SafeAreaProvider } from '../SafeAreaContext';
5
+import { SafeAreaView } from '../SafeAreaView';
6
+import { Metrics } from '../SafeArea.types';
7
+
8
+const INITIAL_METRICS: Metrics = {
9
+  insets: { top: 1, left: 2, right: 3, bottom: 4 },
10
+  frame: { x: 0, y: 0, height: 100, width: 100 },
11
+};
12
+
13
+describe('SafeAreaView', () => {
14
+  it('renders', () => {
15
+    const component = ReactTestRenderer.create(
16
+      <SafeAreaProvider initialMetrics={INITIAL_METRICS}>
17
+        <SafeAreaView>
18
+          <View />
19
+        </SafeAreaView>
20
+      </SafeAreaProvider>,
21
+    );
22
+    expect(component).toMatchSnapshot();
23
+  });
24
+
25
+  it('can override padding styles', () => {
26
+    const component = ReactTestRenderer.create(
27
+      <SafeAreaProvider initialMetrics={INITIAL_METRICS}>
28
+        <SafeAreaView style={{ paddingTop: 0 }}>
29
+          <View />
30
+        </SafeAreaView>
31
+      </SafeAreaProvider>,
32
+    );
33
+    expect(component).toMatchSnapshot();
34
+  });
35
+});

src/__tests__/__snapshots__/index-test.tsx.snap → src/__tests__/__snapshots__/SafeAreaContext-test.tsx.snap 查看文件

@@ -45,10 +45,14 @@ exports[`SafeAreaProvider renders child when inset values are received 2`] = `
45 45
   <View
46 46
     style={
47 47
       Object {
48
-        "bottom": 4,
49
-        "left": 2,
50
-        "right": 3,
51
-        "top": 1,
48
+        "height": 100,
49
+        "left": 0,
50
+        "paddingBottom": 4,
51
+        "paddingLeft": 2,
52
+        "paddingRight": 3,
53
+        "paddingTop": 1,
54
+        "top": 0,
55
+        "width": 100,
52 56
       }
53 57
     }
54 58
   />
@@ -67,10 +71,14 @@ exports[`SafeAreaProvider supports setting initial insets 1`] = `
67 71
   <View
68 72
     style={
69 73
       Object {
70
-        "bottom": 4,
71
-        "left": 2,
72
-        "right": 3,
73
-        "top": 1,
74
+        "height": 100,
75
+        "left": 0,
76
+        "paddingBottom": 4,
77
+        "paddingLeft": 2,
78
+        "paddingRight": 3,
79
+        "paddingTop": 1,
80
+        "top": 0,
81
+        "width": 100,
74 82
       }
75 83
     }
76 84
   />
@@ -97,10 +105,14 @@ exports[`SafeAreaProvider uses inner insets 1`] = `
97 105
     <View
98 106
       style={
99 107
         Object {
100
-          "bottom": 5,
101
-          "left": 3,
102
-          "right": 4,
103
-          "top": 2,
108
+          "height": 16,
109
+          "left": 0,
110
+          "paddingBottom": 5,
111
+          "paddingLeft": 3,
112
+          "paddingRight": 4,
113
+          "paddingTop": 2,
114
+          "top": 0,
115
+          "width": 10,
104 116
         }
105 117
       }
106 118
     />
@@ -128,69 +140,17 @@ exports[`SafeAreaProvider uses parent insets when available 1`] = `
128 140
     <View
129 141
       style={
130 142
         Object {
131
-          "bottom": 4,
132
-          "left": 2,
133
-          "right": 3,
134
-          "top": 1,
135
-        }
136
-      }
137
-    />
138
-  </RNCSafeAreaView>
139
-</RNCSafeAreaView>
140
-`;
141
-
142
-exports[`SafeAreaView can override padding styles 1`] = `
143
-<RNCSafeAreaView
144
-  onInsetsChange={[Function]}
145
-  style={
146
-    Object {
147
-      "flex": 1,
148
-    }
149
-  }
150
->
151
-  <View
152
-    style={
153
-      Array [
154
-        Object {
143
+          "height": 100,
144
+          "left": 0,
155 145
           "paddingBottom": 4,
156 146
           "paddingLeft": 2,
157 147
           "paddingRight": 3,
158 148
           "paddingTop": 1,
159
-        },
160
-        Object {
161
-          "paddingTop": 0,
162
-        },
163
-      ]
164
-    }
165
-  >
166
-    <View />
167
-  </View>
168
-</RNCSafeAreaView>
169
-`;
170
-
171
-exports[`SafeAreaView renders 1`] = `
172
-<RNCSafeAreaView
173
-  onInsetsChange={[Function]}
174
-  style={
175
-    Object {
176
-      "flex": 1,
177
-    }
178
-  }
179
->
180
-  <View
181
-    style={
182
-      Array [
183
-        Object {
184
-          "paddingBottom": 4,
185
-          "paddingLeft": 2,
186
-          "paddingRight": 3,
187
-          "paddingTop": 1,
188
-        },
189
-        undefined,
190
-      ]
191
-    }
192
-  >
193
-    <View />
194
-  </View>
149
+          "top": 0,
150
+          "width": 100,
151
+        }
152
+      }
153
+    />
154
+  </RNCSafeAreaView>
195 155
 </RNCSafeAreaView>
196 156
 `;

+ 57
- 0
src/__tests__/__snapshots__/SafeAreaView-test.tsx.snap 查看文件

@@ -0,0 +1,57 @@
1
+// Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+exports[`SafeAreaView can override padding styles 1`] = `
4
+<RNCSafeAreaView
5
+  onInsetsChange={[Function]}
6
+  style={
7
+    Object {
8
+      "flex": 1,
9
+    }
10
+  }
11
+>
12
+  <View
13
+    style={
14
+      Array [
15
+        Object {
16
+          "paddingBottom": 4,
17
+          "paddingLeft": 2,
18
+          "paddingRight": 3,
19
+          "paddingTop": 1,
20
+        },
21
+        Object {
22
+          "paddingTop": 0,
23
+        },
24
+      ]
25
+    }
26
+  >
27
+    <View />
28
+  </View>
29
+</RNCSafeAreaView>
30
+`;
31
+
32
+exports[`SafeAreaView renders 1`] = `
33
+<RNCSafeAreaView
34
+  onInsetsChange={[Function]}
35
+  style={
36
+    Object {
37
+      "flex": 1,
38
+    }
39
+  }
40
+>
41
+  <View
42
+    style={
43
+      Array [
44
+        Object {
45
+          "paddingBottom": 4,
46
+          "paddingLeft": 2,
47
+          "paddingRight": 3,
48
+          "paddingTop": 1,
49
+        },
50
+        undefined,
51
+      ]
52
+    }
53
+  >
54
+    <View />
55
+  </View>
56
+</RNCSafeAreaView>
57
+`;

+ 0
- 169
src/__tests__/index-test.tsx 查看文件

@@ -1,169 +0,0 @@
1
-import * as React from 'react';
2
-import * as ReactTestRenderer from 'react-test-renderer';
3
-import { View, UIManager } from 'react-native';
4
-import { SafeAreaProvider, SafeAreaView, useSafeArea } from '../index';
5
-import NativeSafeAreaView from '../NativeSafeAreaView';
6
-
7
-const PrintInsetsTestView = () => {
8
-  const insets = useSafeArea();
9
-  return (
10
-    <View
11
-      style={{
12
-        top: insets.top,
13
-        left: insets.left,
14
-        bottom: insets.bottom,
15
-        right: insets.right,
16
-      }}
17
-    />
18
-  );
19
-};
20
-
21
-describe('SafeAreaProvider', () => {
22
-  it('renders', () => {
23
-    const component = ReactTestRenderer.create(<SafeAreaProvider />);
24
-    expect(component).toMatchSnapshot();
25
-  });
26
-
27
-  it('does not render child until inset values are received', () => {
28
-    const component = ReactTestRenderer.create(
29
-      <SafeAreaProvider>
30
-        <PrintInsetsTestView />
31
-      </SafeAreaProvider>,
32
-    );
33
-    expect(component).toMatchSnapshot();
34
-  });
35
-
36
-  it('renders child when inset values are received', () => {
37
-    const component = ReactTestRenderer.create(
38
-      <SafeAreaProvider>
39
-        <PrintInsetsTestView />
40
-      </SafeAreaProvider>,
41
-    );
42
-    expect(component).toMatchSnapshot();
43
-    const { onInsetsChange } = component.root.findByType(
44
-      NativeSafeAreaView,
45
-    ).props;
46
-    ReactTestRenderer.act(() => {
47
-      onInsetsChange({
48
-        nativeEvent: { insets: { top: 1, left: 2, right: 3, bottom: 4 } },
49
-      });
50
-    });
51
-    expect(component).toMatchSnapshot();
52
-  });
53
-
54
-  it('supports setting initial insets', () => {
55
-    const component = ReactTestRenderer.create(
56
-      <SafeAreaProvider
57
-        initialSafeAreaInsets={{ top: 1, left: 2, right: 3, bottom: 4 }}
58
-      >
59
-        <PrintInsetsTestView />
60
-      </SafeAreaProvider>,
61
-    );
62
-    expect(component).toMatchSnapshot();
63
-  });
64
-
65
-  it('uses parent insets when available', () => {
66
-    const component = ReactTestRenderer.create(
67
-      <SafeAreaProvider
68
-        initialSafeAreaInsets={{ top: 1, left: 2, right: 3, bottom: 4 }}
69
-      >
70
-        <SafeAreaProvider>
71
-          <PrintInsetsTestView />
72
-        </SafeAreaProvider>
73
-      </SafeAreaProvider>,
74
-    );
75
-    expect(component).toMatchSnapshot();
76
-  });
77
-
78
-  it('uses inner insets', () => {
79
-    const component = ReactTestRenderer.create(
80
-      <SafeAreaProvider
81
-        initialSafeAreaInsets={{ top: 1, left: 2, right: 3, bottom: 4 }}
82
-      >
83
-        <SafeAreaProvider
84
-          initialSafeAreaInsets={{ top: 2, left: 3, right: 4, bottom: 5 }}
85
-        >
86
-          <PrintInsetsTestView />
87
-        </SafeAreaProvider>
88
-      </SafeAreaProvider>,
89
-    );
90
-    expect(component).toMatchSnapshot();
91
-  });
92
-
93
-  it('throws when no provider is rendered', () => {
94
-    // Silence the React error boundary warning; we expect an uncaught error.
95
-    const consoleErrorMock = jest
96
-      .spyOn(console, 'error')
97
-      .mockImplementation(message => {
98
-        if (message.startsWith('The above error occured in the ')) {
99
-          return;
100
-        }
101
-      });
102
-    expect(() => {
103
-      ReactTestRenderer.create(<PrintInsetsTestView />);
104
-    }).toThrow(
105
-      'No safe area value available. Make sure you are rendering `<SafeAreaProvider>` at the top of your app.',
106
-    );
107
-
108
-    consoleErrorMock.mockRestore();
109
-  });
110
-});
111
-
112
-describe('SafeAreaView', () => {
113
-  it('renders', () => {
114
-    const component = ReactTestRenderer.create(
115
-      <SafeAreaProvider
116
-        initialSafeAreaInsets={{ top: 1, left: 2, right: 3, bottom: 4 }}
117
-      >
118
-        <SafeAreaView>
119
-          <View />
120
-        </SafeAreaView>
121
-      </SafeAreaProvider>,
122
-    );
123
-    expect(component).toMatchSnapshot();
124
-  });
125
-
126
-  it('can override padding styles', () => {
127
-    const component = ReactTestRenderer.create(
128
-      <SafeAreaProvider
129
-        initialSafeAreaInsets={{ top: 1, left: 2, right: 3, bottom: 4 }}
130
-      >
131
-        <SafeAreaView style={{ paddingTop: 0 }}>
132
-          <View />
133
-        </SafeAreaView>
134
-      </SafeAreaProvider>,
135
-    );
136
-    expect(component).toMatchSnapshot();
137
-  });
138
-});
139
-
140
-describe('initialWindowSafeAreaInsets', () => {
141
-  it('is null when no view config is available', () => {
142
-    jest.resetModules();
143
-    expect(require('../index').initialWindowSafeAreaInsets).toBe(null);
144
-  });
145
-
146
-  it('it uses the constant provided by the view config', () => {
147
-    jest.resetModules();
148
-    const testInsets = {
149
-      top: 20,
150
-      left: 0,
151
-      right: 0,
152
-      bottom: 0,
153
-    };
154
-    UIManager.getViewManagerConfig = jest.fn(name => {
155
-      if (name === 'RNCSafeAreaView') {
156
-        return {
157
-          Commands: {},
158
-          Constants: {
159
-            initialWindowSafeAreaInsets: testInsets,
160
-          },
161
-        };
162
-      }
163
-      return { Commands: {} };
164
-    });
165
-
166
-    expect(require('../index').initialWindowSafeAreaInsets).toBe(testInsets);
167
-    expect(UIManager.getViewManagerConfig).toBeCalledWith('RNCSafeAreaView');
168
-  });
169
-});

+ 41
- 0
src/__tests__/initialWindowMetrics-test.tsx 查看文件

@@ -0,0 +1,41 @@
1
+import { UIManager } from 'react-native';
2
+import { Metrics } from '../SafeArea.types';
3
+
4
+describe('initialWindowMetrics', () => {
5
+  it('is null when no view config is available', () => {
6
+    jest.resetModules();
7
+    expect(require('../InitialWindow').initialWindowMetrics).toBe(null);
8
+  });
9
+
10
+  it('it uses the constant provided by the view config', () => {
11
+    jest.resetModules();
12
+    const testMetrics: Metrics = {
13
+      insets: {
14
+        top: 20,
15
+        left: 0,
16
+        right: 0,
17
+        bottom: 0,
18
+      },
19
+      frame: {
20
+        x: 0,
21
+        y: 0,
22
+        height: 100,
23
+        width: 100,
24
+      },
25
+    };
26
+    UIManager.getViewManagerConfig = jest.fn((name) => {
27
+      if (name === 'RNCSafeAreaView') {
28
+        return {
29
+          Commands: {},
30
+          Constants: {
31
+            initialWindowMetrics: testMetrics,
32
+          },
33
+        };
34
+      }
35
+      return { Commands: {} };
36
+    });
37
+
38
+    expect(require('../InitialWindow').initialWindowMetrics).toBe(testMetrics);
39
+    expect(UIManager.getViewManagerConfig).toBeCalledWith('RNCSafeAreaView');
40
+  });
41
+});

+ 4
- 80
src/index.tsx 查看文件

@@ -1,80 +1,4 @@
1
-import * as React from 'react';
2
-import { StyleSheet, View, ViewProps } from 'react-native';
3
-import { EdgeInsets as EdgeInsetsT, InsetChangedEvent } from './SafeArea.types';
4
-import NativeSafeAreaView from './NativeSafeAreaView';
5
-
6
-export { default as initialWindowSafeAreaInsets } from './InitialWindowSafeAreaInsets';
7
-
8
-export const SafeAreaContext = React.createContext<EdgeInsetsT | null>(null);
9
-
10
-export interface SafeAreaViewProps {
11
-  children?: React.ReactNode;
12
-  initialSafeAreaInsets?: EdgeInsetsT | null;
13
-}
14
-
15
-export function SafeAreaProvider({
16
-  children,
17
-  initialSafeAreaInsets,
18
-}: SafeAreaViewProps) {
19
-  const parentInsets = useParentSafeArea();
20
-  const [insets, setInsets] = React.useState<EdgeInsetsT | null | undefined>(
21
-    initialSafeAreaInsets || parentInsets,
22
-  );
23
-  const onInsetsChange = React.useCallback((event: InsetChangedEvent) => {
24
-    setInsets(event.nativeEvent.insets);
25
-  }, []);
26
-
27
-  return (
28
-    <NativeSafeAreaView style={styles.fill} onInsetsChange={onInsetsChange}>
29
-      {insets != null ? (
30
-        <SafeAreaContext.Provider value={insets}>
31
-          {children}
32
-        </SafeAreaContext.Provider>
33
-      ) : null}
34
-    </NativeSafeAreaView>
35
-  );
36
-}
37
-
38
-const styles = StyleSheet.create({
39
-  fill: { flex: 1 },
40
-});
41
-
42
-export const SafeAreaConsumer = SafeAreaContext.Consumer;
43
-
44
-function useParentSafeArea(): React.ContextType<typeof SafeAreaContext> {
45
-  return React.useContext(SafeAreaContext);
46
-}
47
-
48
-export function useSafeArea(): EdgeInsetsT {
49
-  const safeArea = React.useContext(SafeAreaContext);
50
-  if (safeArea == null) {
51
-    throw new Error(
52
-      'No safe area value available. Make sure you are rendering `<SafeAreaProvider>` at the top of your app.',
53
-    );
54
-  }
55
-  return safeArea;
56
-}
57
-
58
-export function SafeAreaView({
59
-  style,
60
-  ...rest
61
-}: ViewProps & { children: React.ReactNode }) {
62
-  const insets = useSafeArea();
63
-
64
-  return (
65
-    <View
66
-      style={[
67
-        {
68
-          paddingTop: insets.top,
69
-          paddingRight: insets.right,
70
-          paddingBottom: insets.bottom,
71
-          paddingLeft: insets.left,
72
-        },
73
-        style,
74
-      ]}
75
-      {...rest}
76
-    />
77
-  );
78
-}
79
-
80
-export type EdgeInsets = EdgeInsetsT;
1
+export * from './SafeAreaContext';
2
+export * from './SafeAreaView';
3
+export * from './InitialWindow';
4
+export * from './SafeArea.types';

+ 5
- 1
tsconfig.json 查看文件

@@ -12,7 +12,11 @@
12 12
     "moduleResolution": "node",
13 13
     "skipLibCheck": true,
14 14
     "lib": ["dom", "es2015", "es2016", "esnext"],
15
-    "jsx": "react-native"
15
+    "jsx": "react-native",
16
+    "baseUrl": ".",
17
+    "paths": {
18
+      "react-native-safe-area-context": ["./src"]
19
+    }
16 20
   },
17 21
   "exclude": ["node_modules"]
18 22
 }

+ 9268
- 1873
yarn.lock
文件差異過大導致無法顯示
查看文件