react-native-blur-vibe 0.1.4 → 0.1.6

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.
@@ -3,10 +3,7 @@ package com.blurvibe
3
3
  import android.content.Context
4
4
  import android.graphics.Color
5
5
  import android.graphics.Outline
6
- import android.os.Handler
7
- import android.os.Looper
8
6
  import android.util.TypedValue
9
- import android.view.Choreographer
10
7
  import android.view.View
11
8
  import android.view.ViewGroup
12
9
  import android.view.ViewOutlineProvider
@@ -16,308 +13,244 @@ import com.qmdeve.blurview.base.BaseBlurViewGroup
16
13
  import com.qmdeve.blurview.widget.BlurViewGroup
17
14
 
18
15
  /**
19
- * BlurVibeView — Optimised Android backdrop-blur (QmBlurView / CSS backdrop-filter parity)
16
+ * BlurVibeView — Android backdrop blur implementation
20
17
  *
21
- * ─── What was killing performance (3 FPS) ────────────────────────────────────
18
+ * Extends QmBlurView's BlurViewGroup a high-performance blur library
19
+ * that correctly implements CSS backdrop-filter: blur() semantics:
20
+ * - Blurs content BEHIND the view, not the view itself
21
+ * - Hardware accelerated via native blur algorithms
22
+ * - Handles scroll, animation, zIndex, absolute positioning correctly
23
+ * - Never causes draw loops or bitmap capture on the JS thread
22
24
  *
23
- * 1. blurRounds = 5
24
- * The single biggest killer. Each "round" is a full downsample → Gaussian → upsample
25
- * pipeline. At 60 fps that's 300 blur operations/second. One round looks identical
26
- * to the human eye and costs 1/5 as much. Fixed: blurRounds = 1.
25
+ * Uses reflection to redirect the blur capture root from the activity
26
+ * decor view to the nearest ReactRootView or react-native-screens Screen,
27
+ * preventing full-screen blur and navigation transition artifacts.
27
28
  *
28
- * 2. Blur radius mapped 0–100 instead of 0–25
29
- * mapBlurAmountToRadius() was returning up to 100.0. QmBlurView's Gaussian kernel
30
- * at radius=100 iterates a ~200-wide kernel per-pixel every frame.
31
- * Fixed: map blurAmount 0–100 → radius 0–25.
32
- *
33
- * 3. OnPreDrawListener fires every frame with no throttling
34
- * The listener was doing full blur work synchronously inside the pre-draw callback,
35
- * blocking the draw thread on every invalidation of every child in the tree.
36
- * Fixed: listener only sets a dirty flag; actual blur work is deferred to a
37
- * Choreographer.FrameCallback which fires at most once-per-vsync.
38
- *
39
- * 4. preDrawListener leaked on re-attach
40
- * Each call to onAttachedToWindow re-added the listener without removing the old one,
41
- * multiplying the per-frame cost every time a modal or navigator re-mounted the view.
42
- * Fixed: detachPreDrawListener() called before every re-attach.
43
- *
44
- * ─── Performance profile after fixes ─────────────────────────────────────────
45
- *
46
- * • blur cost reduced ~40× (5 rounds → 1, radius 100 → 25, gated to 1/vsync)
47
- * • zero JS thread work (Choreographer callback runs on UI thread only)
48
- * • zero GC pressure (no bitmap allocations on hot path)
49
- * • works with: Modal, ScrollView, FlatList, FlashList, ImageBackground,
50
- * Reanimated (both JS and UI thread), react-navigation transitions
29
+ * Credit: approach adapted from sbaiahmed1/react-native-blur
51
30
  */
52
31
  class BlurVibeView(context: Context) : BlurViewGroup(context, null) {
53
32
 
54
- // ── Blur state ─────────────────────────────────────────────────────────────
55
-
56
- private var pendingBlurRadius = DEFAULT_BLUR_RADIUS
33
+ private var currentBlurRadius = DEFAULT_BLUR_RADIUS
57
34
  private var currentOverlayColor = Color.TRANSPARENT
58
35
  private var currentCornerRadius = 0f
59
- private var isSetupDone = false
60
-
61
- // ── Choreographer frame gate ───────────────────────────────────────────────
62
- //
63
- // OnPreDrawListener sets pendingFrame = true and returns immediately (never
64
- // blocks). Choreographer fires frameCallback at the next vsync boundary,
65
- // which calls invalidate() → QmBlurView captures + blurs + draws exactly once.
66
- // pendingFrame prevents multiple queued callbacks stacking up.
67
-
68
- private var pendingFrame = false
69
-
70
- private val frameCallback = Choreographer.FrameCallback {
71
- pendingFrame = false
72
- if (isAttachedToWindow) triggerBlurUpdate()
73
- }
36
+ private var isBlurInitialized = false
74
37
 
75
- // ── PreDraw listener — sets dirty flag only, does zero work ───────────────
76
-
77
- private var attachedRoot: View? = null
78
-
79
- private val preDrawListener = ViewTreeObserver.OnPreDrawListener {
80
- if (!pendingFrame) {
81
- pendingFrame = true
82
- Choreographer.getInstance().postFrameCallback(frameCallback)
38
+ companion object {
39
+ private const val DEFAULT_BLUR_RADIUS = 10f
40
+ private const val MIN_BLUR_AMOUNT = 0f
41
+ private const val MAX_BLUR_AMOUNT = 100f
42
+ private const val MAX_BLUR_RADIUS = 25f // QmBlurView Gaussian kernel designed for 0-25
43
+
44
+ // Maps 0–100 blurAmount to 0–25 QmBlurView radius range
45
+ private fun mapBlurAmountToRadius(amount: Float): Float {
46
+ val clamped = amount.coerceIn(MIN_BLUR_AMOUNT, MAX_BLUR_AMOUNT)
47
+ return (clamped / MAX_BLUR_AMOUNT) * MAX_BLUR_RADIUS
83
48
  }
84
- true // MUST return true — false would block the entire frame draw pass
85
49
  }
86
50
 
87
- // ── Init ──────────────────────────────────────────────────────────────────
88
-
89
51
  init {
90
- super.setBackgroundColor(Color.TRANSPARENT)
52
+ super.setBackgroundColor(currentOverlayColor)
91
53
  clipChildren = true
92
54
  clipToOutline = true
93
-
94
- // THE critical fix #1: 1 round instead of 5.
95
- // A single Gaussian pass on a downsampled bitmap is perceptually identical
96
- // to 5 passes and costs exactly 1/5 as much GPU/CPU time.
97
- blurRounds = 1
98
-
99
- // Aggressive downsample: capture at 1/8 resolution before blurring.
100
- // The blur kernel smooths away all pixel-level detail so 1/8 is sufficient.
101
- // This reduces the bitmap size 64× and the blur kernel work proportionally.
102
- super.setDownsampleFactor(8f)
55
+ blurRounds = 1 // was 5 — single pass is visually identical, 5x cheaper
56
+ super.setDownsampleFactor(8.0f) // was 6 1/64 pixel count, blur hides the difference
103
57
  }
104
58
 
105
- // ── Lifecycle ─────────────────────────────────────────────────────────────
106
-
107
59
  override fun onAttachedToWindow() {
108
60
  super.onAttachedToWindow()
109
- attachPreDrawListenerToOptimalRoot()
110
- if (!isSetupDone) applyPendingBlurConfig()
61
+ if (isBlurInitialized) return
62
+ swapBlurRootToOptimalAncestor()
63
+ initializeBlur()
111
64
  }
112
65
 
113
66
  override fun onDetachedFromWindow() {
114
- detachPreDrawListener()
115
- Choreographer.getInstance().removeFrameCallback(frameCallback)
116
- pendingFrame = false
117
- isSetupDone = false
118
67
  super.onDetachedFromWindow()
68
+ isBlurInitialized = false
119
69
  }
120
70
 
121
- // ── Root attachment ───────────────────────────────────────────────────────
122
-
123
- private fun attachPreDrawListenerToOptimalRoot() {
124
- detachPreDrawListener() // always detach first to prevent listener leaks
71
+ private var frameScheduled = false
125
72
 
126
- val root: ViewGroup = findNearestScreenAncestor()
127
- ?: findNearestReactRootView()
128
- ?: (rootView as? ViewGroup)
129
- ?: return
130
-
131
- attachedRoot = root
132
- root.viewTreeObserver.addOnPreDrawListener(preDrawListener)
133
- redirectQmBlurCaptureRoot(root)
134
- }
135
-
136
- private fun detachPreDrawListener() {
137
- attachedRoot?.viewTreeObserver?.removeOnPreDrawListener(preDrawListener)
138
- attachedRoot = null
73
+ private val frameCallback = android.view.Choreographer.FrameCallback {
74
+ frameScheduled = false
75
+ try { invalidate() } catch (_: Exception) {}
139
76
  }
140
77
 
141
78
  /**
142
- * Redirects QmBlurView's internal bitmap-capture root (mDecorView) to [newRoot]
143
- * via reflection. This scopes QmBlurView's capture to the chosen subtree instead
144
- * of the full activity decor view smaller captures = faster blur.
145
- *
146
- * We do NOT mirror QmBlurView's internal preDrawListener. We own the invalidation
147
- * cycle via our own Choreographer-gated listener above.
79
+ * Redirects QmBlurView's internal preDrawListener from the old root to [newRoot].
80
+ * Also wraps it in a Choreographer gate so blur work fires at most ONCE per vsync,
81
+ * even when many views invalidate simultaneously (scroll, animation, etc).
148
82
  */
149
- private fun redirectQmBlurCaptureRoot(newRoot: ViewGroup) {
83
+ private fun swapBlurRootToOptimalAncestor() {
84
+ val newRoot = findNearestScreenAncestor() ?: findNearestReactRootView() ?: return
85
+
150
86
  try {
151
- val baseField = BlurViewGroup::class.java.getDeclaredField("mBaseBlurViewGroup")
87
+ val blurViewGroupClass = BlurViewGroup::class.java
88
+ val baseField = blurViewGroupClass.getDeclaredField("mBaseBlurViewGroup")
152
89
  baseField.isAccessible = true
153
- val base = baseField.get(this) ?: return
90
+ val baseBlurViewGroup = baseField.get(this) ?: return
154
91
 
155
92
  val baseClass = BaseBlurViewGroup::class.java
156
93
 
157
- val decorField = baseClass.getDeclaredField("mDecorView")
158
- decorField.isAccessible = true
159
- decorField.set(base, newRoot)
160
-
161
- val diffRootField = baseClass.getDeclaredField("mDifferentRoot")
162
- diffRootField.isAccessible = true
163
- diffRootField.setBoolean(base, newRoot.rootView != this.rootView)
164
-
165
- val forceRedrawField = baseClass.getDeclaredField("mForceRedraw")
166
- forceRedrawField.isAccessible = true
167
- forceRedrawField.setBoolean(base, true)
168
-
169
- } catch (_: Exception) {
170
- // Reflection failed (library updated internals).
171
- // Fall back gracefully — blur still works via the decor view.
94
+ val decorViewField = baseClass.getDeclaredField("mDecorView")
95
+ decorViewField.isAccessible = true
96
+ val oldDecorView = decorViewField.get(baseBlurViewGroup) as? View
97
+
98
+ val preDrawListenerField = baseClass.getDeclaredField("preDrawListener")
99
+ preDrawListenerField.isAccessible = true
100
+ val preDrawListener = preDrawListenerField.get(baseBlurViewGroup)
101
+ as? ViewTreeObserver.OnPreDrawListener
102
+
103
+ if (oldDecorView != null && preDrawListener != null) {
104
+ // Remove listener from old root
105
+ oldDecorView.viewTreeObserver.removeOnPreDrawListener(preDrawListener)
106
+
107
+ // Set new root
108
+ decorViewField.set(baseBlurViewGroup, newRoot)
109
+
110
+ // Wrap in Choreographer gate: fires at most once per vsync regardless of
111
+ // how many child invalidations happen in the same frame
112
+ val gatedListener = ViewTreeObserver.OnPreDrawListener {
113
+ if (!frameScheduled) {
114
+ frameScheduled = true
115
+ android.view.Choreographer.getInstance().postFrameCallback(frameCallback)
116
+ }
117
+ true // never block the draw pass
118
+ }
119
+
120
+ // Add gated listener to new root (NOT the original raw listener)
121
+ newRoot.viewTreeObserver.addOnPreDrawListener(gatedListener)
122
+
123
+ // Update mDifferentRoot flag
124
+ val differentRootField = baseClass.getDeclaredField("mDifferentRoot")
125
+ differentRootField.isAccessible = true
126
+ differentRootField.setBoolean(baseBlurViewGroup, newRoot.rootView != this.rootView)
127
+
128
+ // Force redraw
129
+ val forceRedrawField = baseClass.getDeclaredField("mForceRedraw")
130
+ forceRedrawField.isAccessible = true
131
+ forceRedrawField.setBoolean(baseBlurViewGroup, true)
132
+ }
133
+ } catch (e: Exception) {
134
+ // Reflection failed — QmBlurView internals changed
135
+ // Fall back gracefully to default decor view blur root
172
136
  }
173
137
  }
174
138
 
175
- // ── Blur update (fires via Choreographer, once per vsync at most) ─────────
139
+ private fun findNearestScreenAncestor(): ViewGroup? {
140
+ var current = parent
141
+ while (current != null) {
142
+ if (current.javaClass.name == "com.swmansion.rnscreens.Screen") {
143
+ return current as? ViewGroup
144
+ }
145
+ current = current.parent
146
+ }
147
+ return null
148
+ }
176
149
 
177
- private fun triggerBlurUpdate() {
178
- try {
179
- if (!isSetupDone) applyPendingBlurConfig() else invalidate()
180
- } catch (_: Exception) {}
150
+ private fun findNearestReactRootView(): ViewGroup? {
151
+ var current = parent
152
+ while (current != null) {
153
+ if (current.javaClass.name == "com.facebook.react.ReactRootView") {
154
+ return current as? ViewGroup
155
+ }
156
+ current = current.parent
157
+ }
158
+ return null
181
159
  }
182
160
 
183
- private fun applyPendingBlurConfig() {
161
+ private fun initializeBlur() {
162
+ if (isBlurInitialized) return
184
163
  try {
185
- super.setBlurRadius(pendingBlurRadius)
164
+ super.setBlurRadius(currentBlurRadius)
186
165
  super.setOverlayColor(currentOverlayColor)
187
- updateCornerRadiusInternal()
188
- isSetupDone = true
189
- } catch (_: Exception) {
190
- // Not fully attached yet next Choreographer tick will retry
166
+ updateCornerRadius()
167
+ isBlurInitialized = true
168
+ } catch (e: Exception) {
169
+ // Ignore view may not be fully attached yet
191
170
  }
192
171
  }
193
172
 
194
- // ── Public setters (ViewManager → UI thread) ──────────────────────────────
173
+ // MARK: - Public setters
195
174
 
196
- /**
197
- * blurAmount: JS-facing 0–100.
198
- * Mapped to 0–25 internally (QmBlurView Gaussian kernel's designed range).
199
- * Values above 25 produce no visible increase in blur but cost more.
200
- */
201
175
  fun setBlurAmount(amount: Float) {
202
- pendingBlurRadius = mapBlurAmount(amount)
203
- if (isSetupDone) {
204
- try { super.setBlurRadius(pendingBlurRadius) } catch (_: Exception) {}
205
- scheduleBlurFrame()
206
- }
176
+ currentBlurRadius = mapBlurAmountToRadius(amount)
177
+ try { super.setBlurRadius(currentBlurRadius) } catch (e: Exception) {}
207
178
  }
208
179
 
209
180
  fun setOverlayColor(colorString: String?) {
210
181
  currentOverlayColor = parseHexColor(colorString ?: "transparent") ?: Color.TRANSPARENT
211
- if (isSetupDone) {
212
- try {
213
- super.setBackgroundColor(Color.TRANSPARENT)
214
- super.setOverlayColor(currentOverlayColor)
215
- } catch (_: Exception) {}
216
- scheduleBlurFrame()
217
- }
182
+ try {
183
+ super.setBackgroundColor(currentOverlayColor)
184
+ super.setOverlayColor(currentOverlayColor)
185
+ } catch (e: Exception) {}
218
186
  }
219
187
 
220
- /** downsample factor override (1–8). Higher = faster + softer. */
221
- fun setBlurRadius(factor: Int) {
222
- try { super.setDownsampleFactor(factor.coerceIn(1, 8).toFloat()) } catch (_: Exception) {}
223
- scheduleBlurFrame()
188
+ fun setReducedTransparencyFallbackColor(colorString: String?) {
189
+ // Stored for future use — QmBlurView handles accessibility fallback internally
224
190
  }
225
191
 
226
- fun applyBorderRadius(radiusDp: Float) {
227
- currentCornerRadius = radiusDp
228
- updateCornerRadiusInternal()
192
+ fun setBlurRadius(radius: Int) {
193
+ // blurRadius is the Android downscale factor — map to QmBlurView's downsample factor
194
+ val downsample = radius.coerceIn(1, 8).toFloat()
195
+ try { super.setDownsampleFactor(downsample) } catch (e: Exception) {}
229
196
  }
230
197
 
231
- fun setReducedTransparencyFallbackColor(@Suppress("UNUSED_PARAMETER") colorString: String?) {
232
- // Reserved — QmBlurView handles its own reduced-transparency fallback
198
+ fun setBorderRadius(radius: Float) {
199
+ currentCornerRadius = radius
200
+ updateCornerRadius()
233
201
  }
234
202
 
235
- // ── Corner radius ─────────────────────────────────────────────────────────
236
-
237
- private fun updateCornerRadiusInternal() {
238
- val px = TypedValue.applyDimension(
239
- TypedValue.COMPLEX_UNIT_DIP, currentCornerRadius, context.resources.displayMetrics
203
+ private fun updateCornerRadius() {
204
+ val radiusPx = TypedValue.applyDimension(
205
+ TypedValue.COMPLEX_UNIT_DIP,
206
+ currentCornerRadius,
207
+ context.resources.displayMetrics
240
208
  )
241
209
  outlineProvider = object : ViewOutlineProvider() {
242
210
  override fun getOutline(view: View, outline: Outline) {
243
- outline.setRoundRect(0, 0, view.width, view.height, px)
211
+ outline.setRoundRect(0, 0, view.width, view.height, radiusPx)
244
212
  }
245
213
  }
246
- clipToOutline = currentCornerRadius > 0f
247
- try { super.setCornerRadius(px) } catch (_: Exception) {}
248
- }
249
-
250
- // ── Helpers ───────────────────────────────────────────────────────────────
251
-
252
- private fun scheduleBlurFrame() {
253
- if (!pendingFrame) {
254
- pendingFrame = true
255
- Choreographer.getInstance().postFrameCallback(frameCallback)
256
- }
257
- }
258
-
259
- private fun mapBlurAmount(amount: Float): Float =
260
- (amount.coerceIn(0f, 100f) / 100f) * 25f
261
-
262
- // ── Ancestor finders ──────────────────────────────────────────────────────
263
-
264
- private fun findNearestScreenAncestor(): ViewGroup? {
265
- var p = parent
266
- while (p != null) {
267
- if (p.javaClass.name == "com.swmansion.rnscreens.Screen") return p as? ViewGroup
268
- p = (p as? View)?.parent
269
- }
270
- return null
271
- }
272
-
273
- private fun findNearestReactRootView(): ViewGroup? {
274
- var p = parent
275
- while (p != null) {
276
- if (p.javaClass.name == "com.facebook.react.ReactRootView") return p as? ViewGroup
277
- p = (p as? View)?.parent
278
- }
279
- return null
214
+ clipToOutline = true
215
+ try { super.setCornerRadius(radiusPx) } catch (e: Exception) {}
280
216
  }
281
217
 
282
- // ── React Native layout passthrough ───────────────────────────────────────
283
-
218
+ // React Native handles layout prevent superclass from interfering
284
219
  override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
285
- // Yoga handles all child layout. Calling super here would cause QmBlurView's
286
- // FrameLayout logic to fight RN's layout system.
220
+ // No-op: layout handled by React Native's Yoga engine
287
221
  }
288
222
 
289
- // ── Color parser ──────────────────────────────────────────────────────────
290
- // Supports: "transparent", "#RGB", "#RRGGBB", "#RRGGBBAA", named colors
291
-
292
- private fun parseHexColor(s: String): Int? {
293
- val t = s.trim()
294
- if (t.equals("transparent", ignoreCase = true)) return Color.TRANSPARENT
295
- if (!t.startsWith("#")) return try { t.toColorInt() } catch (_: Exception) { null }
296
- val hex = t.removePrefix("#")
223
+ // MARK: - Color parser
224
+ // Supports: "transparent", "#RGB", "#RRGGBB", "#RRGGBBAA"
225
+ private fun parseHexColor(colorString: String): Int? {
226
+ val s = colorString.trim()
227
+ if (s.equals("transparent", ignoreCase = true)) return Color.TRANSPARENT
228
+ if (!s.startsWith("#")) {
229
+ return try { s.toColorInt() } catch (e: Exception) { null }
230
+ }
231
+ val hex = s.removePrefix("#")
297
232
  return try {
298
233
  when (hex.length) {
299
- 3 -> Color.argb(255,
234
+ 3 -> Color.argb(
235
+ 255,
300
236
  hex[0].toString().repeat(2).toInt(16),
301
237
  hex[1].toString().repeat(2).toInt(16),
302
- hex[2].toString().repeat(2).toInt(16))
303
- 6 -> Color.argb(255,
238
+ hex[2].toString().repeat(2).toInt(16)
239
+ )
240
+ 6 -> Color.argb(
241
+ 255,
304
242
  hex.substring(0, 2).toInt(16),
305
243
  hex.substring(2, 4).toInt(16),
306
- hex.substring(4, 6).toInt(16))
244
+ hex.substring(4, 6).toInt(16)
245
+ )
307
246
  8 -> Color.argb(
308
- hex.substring(6, 8).toInt(16), // alpha is LAST byte in #RRGGBBAA
247
+ hex.substring(6, 8).toInt(16), // AA is last in #RRGGBBAA
309
248
  hex.substring(0, 2).toInt(16),
310
249
  hex.substring(2, 4).toInt(16),
311
- hex.substring(4, 6).toInt(16))
250
+ hex.substring(4, 6).toInt(16)
251
+ )
312
252
  else -> null
313
253
  }
314
- } catch (_: NumberFormatException) { null }
315
- }
316
-
317
- // ── Constants ─────────────────────────────────────────────────────────────
318
-
319
- companion object {
320
- // blurAmount=10 → radius 2.5 — a gentle, performant default
321
- private const val DEFAULT_BLUR_RADIUS = 2.5f
254
+ } catch (e: NumberFormatException) { null }
322
255
  }
323
256
  }
@@ -7,8 +7,8 @@ import com.facebook.react.uimanager.annotations.ReactProp
7
7
  /**
8
8
  * BlurVibeViewManager
9
9
  *
10
- * ViewGroupManager because BlurVibeView ( BlurViewGroupFrameLayout) hosts
11
- * React children. needsCustomLayoutForChildren() = false lets Yoga own layout.
10
+ * ViewGroupManager BlurVibeView (which extends BlurViewGroup/FrameLayout)
11
+ * hosts React children, so we must use ViewGroupManager, not SimpleViewManager.
12
12
  */
13
13
  class BlurVibeViewManager : ViewGroupManager<BlurVibeView>() {
14
14
 
@@ -17,30 +17,35 @@ class BlurVibeViewManager : ViewGroupManager<BlurVibeView>() {
17
17
  override fun createViewInstance(context: ThemedReactContext) = BlurVibeView(context)
18
18
 
19
19
  @ReactProp(name = "blurAmount", defaultFloat = 10f)
20
- fun setBlurAmount(view: BlurVibeView, amount: Float) = view.setBlurAmount(amount)
20
+ fun setBlurAmount(view: BlurVibeView, amount: Float) {
21
+ view.setBlurAmount(amount)
22
+ }
21
23
 
22
24
  @ReactProp(name = "blurType")
23
25
  fun setBlurType(view: BlurVibeView, type: String?) {
24
- // No-op on Android — blurType is an iOS UIBlurEffectStyle concept only
26
+ // No-op on Android — blurType maps to iOS UIBlurEffectStyle only
25
27
  }
26
28
 
27
29
  @ReactProp(name = "overlayColor")
28
- fun setOverlayColor(view: BlurVibeView, color: String?) = view.setOverlayColor(color)
30
+ fun setOverlayColor(view: BlurVibeView, color: String?) {
31
+ view.setOverlayColor(color)
32
+ }
29
33
 
30
34
  @ReactProp(name = "reducedTransparencyFallbackColor")
31
- fun setReducedTransparencyFallbackColor(view: BlurVibeView, color: String?) =
35
+ fun setReducedTransparencyFallbackColor(view: BlurVibeView, color: String?) {
32
36
  view.setReducedTransparencyFallbackColor(color)
37
+ }
33
38
 
34
39
  @ReactProp(name = "blurRadius", defaultInt = 4)
35
- fun setBlurRadius(view: BlurVibeView, radius: Int) = view.setBlurRadius(radius)
40
+ fun setBlurRadius(view: BlurVibeView, radius: Int) {
41
+ view.setBlurRadius(radius)
42
+ }
36
43
 
37
44
  @ReactProp(name = "borderRadius", defaultFloat = 0f)
38
- fun setBlurBorderRadius(view: BlurVibeView, radius: Float) = view.applyBorderRadius(radius)
39
-
40
- override fun onDropViewInstance(view: BlurVibeView) {
41
- super.onDropViewInstance(view)
45
+ fun setBlurBorderRadius(view: BlurVibeView, radius: Float) {
46
+ view.setBorderRadius(radius)
42
47
  }
43
48
 
44
- // Yoga drives all child layout — return false
49
+ // React Native's Yoga handles child layout — return false
45
50
  override fun needsCustomLayoutForChildren(): Boolean = false
46
51
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-blur-vibe",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "React Native package implementing Blur View in iOS and Android",
5
5
  "main": "./lib/commonjs/index.js",
6
6
  "module": "./lib/module/index.js",