@react-native-hero/dimension 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -40,6 +40,9 @@ $ react-native link @react-native-hero/dimension
40
40
 
41
41
  ```js
42
42
  import {
43
+ init,
44
+ addListener,
45
+
43
46
  statusBarHeight,
44
47
  navigationBarHeight,
45
48
  screenSize,
@@ -51,6 +54,9 @@ import {
51
54
  getSafeArea,
52
55
  } from '@react-native-hero/dimension'
53
56
 
57
+ // In your App.js, call init()
58
+ init()
59
+
54
60
  // The getXxx methods is used to get the latest dimension info asynchronously.
55
61
  // If your app will not change the dimension info, you can just use the corresponding variables.
56
62
 
@@ -73,4 +79,12 @@ getSafeArea().then(data => {
73
79
  data.bottom
74
80
  data.left
75
81
  })
82
+
83
+ // You have to listen dimension change in android app.
84
+ addListener('change', function (data) {
85
+ data.statusBarHeight
86
+ data.navigationBarHeight
87
+ data.screenSize
88
+ data.safeArea
89
+ })
76
90
  ```
@@ -1,14 +1,18 @@
1
1
  package com.github.reactnativehero.dimension
2
2
 
3
- import android.os.Build
4
- import android.view.Display
5
- import android.content.Context.WINDOW_SERVICE
3
+ import android.app.Activity
6
4
  import android.graphics.Point
7
5
  import android.graphics.Rect
6
+ import android.os.Build
7
+ import android.os.Handler
8
+ import android.os.Looper
9
+ import android.util.Size
8
10
  import android.view.WindowManager
11
+ import androidx.core.view.OnApplyWindowInsetsListener
12
+ import androidx.core.view.ViewCompat
13
+ import androidx.core.view.WindowInsetsCompat
9
14
  import com.facebook.react.bridge.*
10
- import java.lang.Exception
11
- import java.util.HashMap
15
+ import com.facebook.react.modules.core.DeviceEventManagerModule
12
16
 
13
17
  class RNTDimensionModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
14
18
 
@@ -16,52 +20,132 @@ class RNTDimensionModule(private val reactContext: ReactApplicationContext) : Re
16
20
  reactApplicationContext.resources.displayMetrics.density
17
21
  }
18
22
 
23
+ private var statusBarHeight = 0
24
+ private var navigationBarHeight = 0
25
+
26
+ private var cutoutTop = 0
27
+ private var cutoutRight = 0
28
+ private var cutoutBottom = 0
29
+ private var cutoutLeft = 0
30
+
19
31
  override fun getName(): String {
20
32
  return "RNTDimension"
21
33
  }
22
34
 
23
- override fun getConstants(): Map<String, Any>? {
35
+ override fun getConstants(): Map<String, Any> {
24
36
 
25
37
  val constants: MutableMap<String, Any> = HashMap()
26
38
 
27
- constants["DIMENSION_STATUS_BAR_HEIGHT"] = getStatusBarHeight()
28
- constants["DIMENSION_NAVIGATION_BAR_HEIGHT"] = getNavigationBarHeight()
39
+ constants["STATUS_BAR_HEIGHT"] = getStatusBarHeightData()
40
+ constants["NAVIGATION_BAR_HEIGHT"] = getNavigationBarHeightData()
29
41
 
30
- val screenSize = getScreenSizeMap()
31
- constants["DIMENSION_SCREEN_WIDTH"] = screenSize.getInt("width")
32
- constants["DIMENSION_SCREEN_HEIGHT"] = screenSize.getInt("height")
42
+ val screenSize = getScreenSizeData()
43
+ constants["SCREEN_WIDTH"] = screenSize.width
44
+ constants["SCREEN_HEIGHT"] = screenSize.height
33
45
 
34
- val safeArea = getSafeAreaMap()
35
- constants["DIMENSION_SAFE_AREA_TOP"] = safeArea.getInt("top")
36
- constants["DIMENSION_SAFE_AREA_RIGHT"] = safeArea.getInt("right")
37
- constants["DIMENSION_SAFE_AREA_BOTTOM"] = safeArea.getInt("bottom")
38
- constants["DIMENSION_SAFE_AREA_LEFT"] = safeArea.getInt("left")
46
+ val safeArea = getSafeAreaData()
47
+ constants["SAFE_AREA_TOP"] = safeArea.top
48
+ constants["SAFE_AREA_RIGHT"] = safeArea.right
49
+ constants["SAFE_AREA_BOTTOM"] = safeArea.bottom
50
+ constants["SAFE_AREA_LEFT"] = safeArea.left
39
51
 
40
52
  return constants
41
53
 
42
54
  }
43
55
 
44
56
  @ReactMethod
45
- fun getStatusBarHeight(promise: Promise) {
57
+ fun init(promise: Promise) {
58
+
59
+ lateinit var waitActivity: () -> Unit
60
+
61
+ val handler = fun (activity: Activity?) {
62
+ val listener = OnApplyWindowInsetsListener { _, insets ->
63
+
64
+ val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
65
+ val cutoutInsets = insets.getInsets(WindowInsetsCompat.Type.displayCutout())
66
+
67
+ var isChange = false
68
+
69
+ if (statusBarHeight != systemBarInsets.top) {
70
+ statusBarHeight = systemBarInsets.top
71
+ isChange = true
72
+ }
73
+ if (navigationBarHeight != systemBarInsets.bottom) {
74
+ navigationBarHeight = systemBarInsets.bottom
75
+ isChange = true
76
+ }
77
+ if (cutoutTop != cutoutInsets.top) {
78
+ cutoutTop = cutoutInsets.top
79
+ isChange = true
80
+ }
81
+ if (cutoutRight != cutoutInsets.right) {
82
+ cutoutRight = cutoutInsets.right
83
+ isChange = true
84
+ }
85
+ if (cutoutBottom != cutoutInsets.bottom) {
86
+ cutoutBottom = cutoutInsets.bottom
87
+ isChange = true
88
+ }
89
+ if (cutoutLeft != cutoutInsets.left) {
90
+ cutoutLeft = cutoutInsets.left
91
+ isChange = true
92
+ }
93
+
94
+ if (isChange) {
95
+ val screenSizeData = getScreenSizeData()
96
+ val screenSizeMap = Arguments.createMap()
97
+ screenSizeMap.putInt("width", screenSizeData.width)
98
+ screenSizeMap.putInt("height", screenSizeData.height)
99
+
100
+ val safeAreaData = getSafeAreaData()
101
+ val safeAreaMap = Arguments.createMap()
102
+ safeAreaMap.putInt("top", safeAreaData.top)
103
+ safeAreaMap.putInt("right", safeAreaData.right)
104
+ safeAreaMap.putInt("bottom", safeAreaData.bottom)
105
+ safeAreaMap.putInt("left", safeAreaData.left)
106
+
107
+ val map = Arguments.createMap()
108
+ map.putInt("statusBarHeight", getStatusBarHeightData())
109
+ map.putInt("navigationBarHeight", getNavigationBarHeightData())
110
+ map.putMap("screenSize", screenSizeMap)
111
+ map.putMap("safeArea", safeAreaMap)
112
+
113
+ sendEvent("change", map)
114
+ }
115
+
116
+ insets
117
+ }
118
+ if (activity != null) {
119
+ activity.runOnUiThread {
120
+ val decorView = activity.window.decorView
121
+ ViewCompat.setOnApplyWindowInsetsListener(decorView, listener)
122
+ decorView.requestApplyInsets()
123
+
124
+ val map = Arguments.createMap()
125
+ promise.resolve(map)
126
+ }
127
+ } else {
128
+ waitActivity()
129
+ }
130
+ }
46
131
 
47
- val map = Arguments.createMap()
48
- map.putInt("height", getStatusBarHeight())
132
+ waitActivity = fun () {
133
+ Handler(Looper.getMainLooper()).postDelayed({
134
+ handler(currentActivity)
135
+ }, 200)
136
+ }
49
137
 
50
- promise.resolve(map)
138
+ handler(currentActivity)
51
139
 
52
140
  }
53
141
 
54
- private fun getStatusBarHeight(): Int {
142
+ @ReactMethod
143
+ fun getStatusBarHeight(promise: Promise) {
55
144
 
56
- val resources = reactApplicationContext.resources
57
- val resId = resources.getIdentifier("status_bar_height", "dimen", "android")
145
+ val map = Arguments.createMap()
146
+ map.putInt("height", getStatusBarHeightData())
58
147
 
59
- return if (resId > 0) {
60
- (resources.getDimensionPixelSize(resId) / density).toInt()
61
- }
62
- else {
63
- 0
64
- }
148
+ promise.resolve(map)
65
149
 
66
150
  }
67
151
 
@@ -69,109 +153,81 @@ class RNTDimensionModule(private val reactContext: ReactApplicationContext) : Re
69
153
  fun getNavigationBarHeight(promise: Promise) {
70
154
 
71
155
  val map = Arguments.createMap()
72
- map.putInt("height", getNavigationBarHeight())
156
+ map.putInt("height", getNavigationBarHeightData())
73
157
 
74
158
  promise.resolve(map)
75
159
 
76
160
  }
77
161
 
78
- private fun getNavigationBarHeight(): Int {
79
-
80
- val window = currentActivity?.window ?: return 0
81
-
82
- // getScreenSize() 方法在某些手机上返回的是内容区域的尺寸
83
- // 导致这里返回的是 navigation bar + status bar 的高度
84
- // 因此我们改变思路,获取内容区域的位置信息,这样就能求出真实的 navigation bar 的高度了
85
-
86
- val realScreenSize = getRealScreenSize()
87
-
88
- val rect = Rect()
89
-
90
- window.decorView.getWindowVisibleDisplayFrame(rect)
91
-
92
- return ((realScreenSize.y - rect.bottom) / density).toInt()
93
-
94
- }
95
-
96
162
  @ReactMethod
97
163
  fun getScreenSize(promise: Promise) {
98
164
 
99
- promise.resolve(getScreenSizeMap())
100
-
101
- }
102
-
103
- private fun getScreenSizeMap(): WritableMap {
104
-
105
- // 跟 ios 保持一致,获取的是物理屏尺寸
106
- val screenSize = getRealScreenSize()
107
-
108
165
  val map = Arguments.createMap()
109
- map.putInt("width", (screenSize.x / density).toInt())
110
- map.putInt("height", (screenSize.y / density).toInt())
166
+ val data = getScreenSizeData()
111
167
 
112
- return map
168
+ map.putInt("width", data.width)
169
+ map.putInt("height", data.height)
170
+
171
+ promise.resolve(map)
113
172
 
114
173
  }
115
174
 
116
175
  @ReactMethod
117
176
  fun getSafeArea(promise: Promise) {
118
177
 
119
- promise.resolve(getSafeAreaMap())
120
-
121
- }
122
-
123
- private fun getSafeAreaMap(): WritableMap {
124
-
125
178
  val map = Arguments.createMap()
126
- map.putInt("top", getStatusBarHeight())
127
- map.putInt("right", 0)
128
- map.putInt("bottom", 0)
129
- map.putInt("left", 0)
130
-
131
- // P 之前的版本都是厂商私有实现,懒得折腾了
132
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
133
- currentActivity?.window.decorView.rootWindowInsets?.displayCutout?.let {
134
- map.putInt("top", (it.safeInsetTop / density).toInt())
135
- map.putInt("right", (it.safeInsetRight / density).toInt())
136
- map.putInt("bottom", (it.safeInsetBottom / density).toInt())
137
- map.putInt("left", (it.safeInsetLeft / density).toInt())
138
- }
139
- }
140
-
141
- return map
179
+ val data = getSafeAreaData()
142
180
 
143
- }
181
+ map.putInt("top", data.top)
182
+ map.putInt("right", data.right)
183
+ map.putInt("bottom", data.bottom)
184
+ map.putInt("left", data.left)
144
185
 
145
- private fun getScreenSize(): Point {
146
-
147
- val display = (reactContext.getSystemService(WINDOW_SERVICE) as WindowManager).defaultDisplay
148
- val size = Point()
149
-
150
- display.getSize(size)
186
+ promise.resolve(map)
151
187
 
152
- return size
188
+ }
153
189
 
190
+ private fun getScreenSizeData(): Size {
191
+ // 跟 ios 保持一致,获取的是物理屏尺寸
192
+ var screenWidth = 0
193
+ var screenHeight = 0
194
+
195
+ val windowManager = reactContext.getSystemService(WindowManager::class.java)
196
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
197
+ // Android 11+
198
+ val windowMetrics = windowManager.currentWindowMetrics
199
+ screenWidth = windowMetrics.bounds.width() // 屏幕总宽度(像素)
200
+ screenHeight = windowMetrics.bounds.height() // 屏幕总高度(像素)
201
+ } else {
202
+ // 旧版本兼容方案(Android 5.0~10)
203
+ val point = Point()
204
+ windowManager.defaultDisplay.getRealSize(point)
205
+ screenWidth = point.x
206
+ screenHeight = point.y
207
+ }
208
+ return Size(toReactUnit(screenWidth), toReactUnit(screenHeight))
154
209
  }
155
210
 
156
- private fun getRealScreenSize(): Point {
211
+ private fun getStatusBarHeightData(): Int {
212
+ return toReactUnit(statusBarHeight)
213
+ }
157
214
 
158
- val display = (reactContext.getSystemService(WINDOW_SERVICE) as WindowManager).defaultDisplay
159
- val size = Point()
215
+ private fun getNavigationBarHeightData(): Int {
216
+ return toReactUnit(navigationBarHeight)
217
+ }
160
218
 
161
- // Android 4.2
162
- if (Build.VERSION.SDK_INT >= 17) {
163
- display.getRealSize(size)
164
- }
165
- else if (Build.VERSION.SDK_INT >= 14) {
166
- try {
167
- size.x = Display::class.java.getMethod("getRawWidth").invoke(display) as Int
168
- size.y = Display::class.java.getMethod("getRawHeight").invoke(display) as Int
169
- } catch (e: Exception) {
170
- }
171
- }
219
+ private fun getSafeAreaData(): Rect {
220
+ return Rect(toReactUnit(cutoutLeft), toReactUnit(statusBarHeight), toReactUnit(cutoutRight), toReactUnit(cutoutBottom))
221
+ }
172
222
 
173
- return size
223
+ private fun toReactUnit(value: Int): Int {
224
+ return (value / density).toInt()
225
+ }
174
226
 
227
+ private fun sendEvent(eventName: String, params: WritableMap) {
228
+ reactContext
229
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
230
+ .emit(eventName, params)
175
231
  }
176
232
 
177
- }
233
+ }
package/index.js CHANGED
@@ -1,22 +1,28 @@
1
1
 
2
- import { NativeModules } from 'react-native'
2
+ import { NativeEventEmitter, NativeModules } from 'react-native'
3
3
 
4
4
  const { RNTDimension } = NativeModules
5
5
 
6
- export const statusBarHeight = RNTDimension.DIMENSION_STATUS_BAR_HEIGHT
6
+ const eventEmitter = new NativeEventEmitter(RNTDimension)
7
7
 
8
- export const navigationBarHeight = RNTDimension.DIMENSION_NAVIGATION_BAR_HEIGHT
8
+ export const statusBarHeight = RNTDimension.STATUS_BAR_HEIGHT
9
+
10
+ export const navigationBarHeight = RNTDimension.NAVIGATION_BAR_HEIGHT
9
11
 
10
12
  export const screenSize = {
11
- width: RNTDimension.DIMENSION_SCREEN_WIDTH,
12
- height: RNTDimension.DIMENSION_SCREEN_HEIGHT,
13
+ width: RNTDimension.SCREEN_WIDTH,
14
+ height: RNTDimension.SCREEN_HEIGHT,
13
15
  }
14
16
 
15
17
  export const safeArea = {
16
- top: RNTDimension.DIMENSION_SAFE_AREA_TOP,
17
- right: RNTDimension.DIMENSION_SAFE_AREA_RIGHT,
18
- bottom: RNTDimension.DIMENSION_SAFE_AREA_BOTTOM,
19
- left: RNTDimension.DIMENSION_SAFE_AREA_LEFT,
18
+ top: RNTDimension.SAFE_AREA_TOP,
19
+ right: RNTDimension.SAFE_AREA_RIGHT,
20
+ bottom: RNTDimension.SAFE_AREA_BOTTOM,
21
+ left: RNTDimension.SAFE_AREA_LEFT,
22
+ }
23
+
24
+ export function init() {
25
+ return RNTDimension.init()
20
26
  }
21
27
 
22
28
  export function getStatusBarHeight() {
@@ -33,4 +39,8 @@ export function getScreenSize() {
33
39
 
34
40
  export function getSafeArea() {
35
41
  return RNTDimension.getSafeArea()
36
- }
42
+ }
43
+
44
+ export function addListener(type, listener) {
45
+ return eventEmitter.addListener(type, listener)
46
+ }
@@ -1,14 +1,16 @@
1
1
  #import "RNTDimension.h"
2
2
 
3
- CGFloat getStatusBarHeight() {
3
+ @implementation RNTDimension
4
+
5
+ static CGFloat getStatusBarHeight() {
4
6
  return UIApplication.sharedApplication.statusBarFrame.size.height;
5
7
  }
6
8
 
7
- CGFloat getNavigationBarHeight() {
9
+ static CGFloat getNavigationBarHeight() {
8
10
  return 0;
9
11
  }
10
12
 
11
- NSDictionary* getScreenSize() {
13
+ static NSDictionary* getScreenSize() {
12
14
 
13
15
  CGRect bounds = UIScreen.mainScreen.bounds;
14
16
 
@@ -19,7 +21,7 @@ NSDictionary* getScreenSize() {
19
21
 
20
22
  }
21
23
 
22
- NSDictionary* getSafeArea() {
24
+ static NSDictionary* getSafeArea() {
23
25
 
24
26
  if (@available(iOS 11.0, *)) {
25
27
  UIWindow* window = [[UIApplication sharedApplication] keyWindow];
@@ -41,8 +43,6 @@ NSDictionary* getSafeArea() {
41
43
 
42
44
  }
43
45
 
44
- @implementation RNTDimension
45
-
46
46
  + (BOOL)requiresMainQueueSetup {
47
47
  return YES;
48
48
  }
@@ -55,19 +55,23 @@ NSDictionary* getSafeArea() {
55
55
  NSDictionary *screenSize = getScreenSize();
56
56
  NSDictionary *safeArea = getSafeArea();
57
57
  return @{
58
- @"DIMENSION_STATUS_BAR_HEIGHT": @(getStatusBarHeight()),
59
- @"DIMENSION_NAVIGATION_BAR_HEIGHT": @(getNavigationBarHeight()),
60
- @"DIMENSION_SCREEN_WIDTH": screenSize[@"width"],
61
- @"DIMENSION_SCREEN_HEIGHT": screenSize[@"height"],
62
- @"DIMENSION_SAFE_AREA_TOP": safeArea[@"top"],
63
- @"DIMENSION_SAFE_AREA_RIGHT": safeArea[@"right"],
64
- @"DIMENSION_SAFE_AREA_BOTTOM": safeArea[@"bottom"],
65
- @"DIMENSION_SAFE_AREA_LEFT": safeArea[@"left"],
58
+ @"STATUS_BAR_HEIGHT": @(getStatusBarHeight()),
59
+ @"NAVIGATION_BAR_HEIGHT": @(getNavigationBarHeight()),
60
+ @"SCREEN_WIDTH": screenSize[@"width"],
61
+ @"SCREEN_HEIGHT": screenSize[@"height"],
62
+ @"SAFE_AREA_TOP": safeArea[@"top"],
63
+ @"SAFE_AREA_RIGHT": safeArea[@"right"],
64
+ @"SAFE_AREA_BOTTOM": safeArea[@"bottom"],
65
+ @"SAFE_AREA_LEFT": safeArea[@"left"],
66
66
  };
67
67
  }
68
68
 
69
69
  RCT_EXPORT_MODULE(RNTDimension);
70
70
 
71
+ RCT_EXPORT_METHOD(init:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
72
+ resolve(@{});
73
+ }
74
+
71
75
  RCT_EXPORT_METHOD(getStatusBarHeight:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
72
76
 
73
77
  resolve(@{
@@ -96,4 +100,4 @@ RCT_EXPORT_METHOD(getSafeArea:(RCTPromiseResolveBlock)resolve reject:(RCTPromise
96
100
 
97
101
  }
98
102
 
99
- @end
103
+ @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-hero/dimension",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "description": "react native dimension",
5
5
  "main": "index.js",
6
6
  "scripts": {