@sbaiahmed1/react-native-blur 4.6.2-beta.0 → 4.6.3-beta.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 +16 -11
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/BlurType.kt +12 -19
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurSwitch.kt +19 -1
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurSwitchManager.kt +5 -0
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurView.kt +98 -135
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurViewManager.kt +25 -0
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeProgressiveBlurView.kt +21 -1
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeProgressiveBlurViewManager.kt +5 -0
- package/ios/Helpers/BlurStyleHelpers.swift +17 -0
- package/ios/Views/AdvancedBlurView.swift +8 -5
- package/ios/Views/BasicColoredView.swift +1 -19
- package/ios/Views/BlurEffectView.swift +19 -19
- package/ios/Views/LiquidGlassContainerView.swift +4 -7
- package/ios/Views/ProgressiveBlurView.swift +8 -3
- package/ios/Views/VariableBlurView.swift +0 -11
- package/ios/Views/VibrancyEffectView.swift +3 -12
- package/lib/module/BlurSwitch.js +11 -6
- package/lib/module/BlurSwitch.js.map +1 -1
- package/lib/module/BlurView.js +2 -0
- package/lib/module/BlurView.js.map +1 -1
- package/lib/module/LiquidGlassContainer.js.map +1 -1
- package/lib/module/LiquidGlassView.js.map +1 -1
- package/lib/module/ProgressiveBlurView.js +3 -0
- package/lib/module/ProgressiveBlurView.js.map +1 -1
- package/lib/module/ReactNativeBlurSwitchNativeComponent.ts +2 -37
- package/lib/module/ReactNativeBlurViewNativeComponent.ts +2 -0
- package/lib/module/ReactNativeLiquidGlassContainerNativeComponent.ts +0 -5
- package/lib/module/ReactNativeLiquidGlassViewNativeComponent.ts +0 -35
- package/lib/module/ReactNativeProgressiveBlurViewNativeComponent.ts +2 -0
- package/lib/typescript/src/BlurSwitch.d.ts +10 -0
- package/lib/typescript/src/BlurSwitch.d.ts.map +1 -1
- package/lib/typescript/src/BlurView.d.ts +11 -2
- package/lib/typescript/src/BlurView.d.ts.map +1 -1
- package/lib/typescript/src/LiquidGlassContainer.d.ts +3 -2
- package/lib/typescript/src/LiquidGlassContainer.d.ts.map +1 -1
- package/lib/typescript/src/LiquidGlassView.d.ts +25 -15
- package/lib/typescript/src/LiquidGlassView.d.ts.map +1 -1
- package/lib/typescript/src/ProgressiveBlurView.d.ts +11 -2
- package/lib/typescript/src/ProgressiveBlurView.d.ts.map +1 -1
- package/lib/typescript/src/ReactNativeBlurSwitchNativeComponent.d.ts +2 -32
- package/lib/typescript/src/ReactNativeBlurSwitchNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts +2 -1
- package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/ReactNativeLiquidGlassContainerNativeComponent.d.ts +0 -5
- package/lib/typescript/src/ReactNativeLiquidGlassContainerNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/ReactNativeLiquidGlassViewNativeComponent.d.ts +0 -30
- package/lib/typescript/src/ReactNativeLiquidGlassViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/ReactNativeProgressiveBlurViewNativeComponent.d.ts +2 -1
- package/lib/typescript/src/ReactNativeProgressiveBlurViewNativeComponent.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/BlurSwitch.tsx +23 -3
- package/src/BlurView.tsx +14 -2
- package/src/LiquidGlassContainer.tsx +3 -2
- package/src/LiquidGlassView.tsx +25 -15
- package/src/ProgressiveBlurView.tsx +15 -2
- package/src/ReactNativeBlurSwitchNativeComponent.ts +2 -37
- package/src/ReactNativeBlurViewNativeComponent.ts +2 -0
- package/src/ReactNativeLiquidGlassContainerNativeComponent.ts +0 -5
- package/src/ReactNativeLiquidGlassViewNativeComponent.ts +0 -35
- package/src/ReactNativeProgressiveBlurViewNativeComponent.ts +2 -0
- package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeBlurViewManagerDelegate.java +0 -53
- package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeBlurViewManagerInterface.java +0 -25
- package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeGlassEffectContainerManagerDelegate.java +0 -53
- package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeGlassEffectContainerManagerInterface.java +0 -25
- package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeGlassViewManagerDelegate.java +0 -38
- package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeGlassViewManagerInterface.java +0 -20
- package/android/app/build/generated/source/codegen/jni/CMakeLists.txt +0 -36
- package/android/app/build/generated/source/codegen/jni/ReactNativeBlurViewSpec-generated.cpp +0 -22
- package/android/app/build/generated/source/codegen/jni/ReactNativeBlurViewSpec.h +0 -24
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ComponentDescriptors.cpp +0 -23
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ComponentDescriptors.h +0 -25
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/EventEmitters.cpp +0 -17
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/EventEmitters.h +0 -30
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/Props.cpp +0 -46
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/Props.h +0 -131
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ReactNativeBlurViewSpecJSI-generated.cpp +0 -17
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ReactNativeBlurViewSpecJSI.h +0 -19
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ShadowNodes.cpp +0 -18
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ShadowNodes.h +0 -43
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/States.cpp +0 -16
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/States.h +0 -41
package/README.md
CHANGED
|
@@ -626,6 +626,7 @@ All props are optional and have sensible defaults.
|
|
|
626
626
|
| ---------------------------------- | ------------ | ----------- | ----------------------------------------------------------------------------- |
|
|
627
627
|
| `blurType` | `BlurType` | `'xlight'` | The type of blur effect to apply |
|
|
628
628
|
| `blurAmount` | `number` | `10.0` | The intensity of the blur effect (0-100) |
|
|
629
|
+
| `blurRounds` | `number` | `5` | The number of blur interactions must be an integer value (1-15) |
|
|
629
630
|
| `ignoreSafeArea` | `boolean` | `true` | (iOS only) Controls whether the blur effect should ignore all safe area edges |
|
|
630
631
|
| `reducedTransparencyFallbackColor` | `string` | `'#FFFFFF'` | Fallback color when reduced transparency is enabled |
|
|
631
632
|
| `overlayColor` | `ColorValue` | `undefined` | The overlay color to apply on top of the blur effect |
|
|
@@ -647,16 +648,17 @@ All props are optional and have sensible defaults.
|
|
|
647
648
|
|
|
648
649
|
All props are optional and have sensible defaults.
|
|
649
650
|
|
|
650
|
-
| Prop | Type | Default | Description
|
|
651
|
-
| ---------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------- |
|
|
652
|
-
| `blurType` | `BlurType` | `'regular'` | The type of blur effect to apply
|
|
653
|
-
| `blurAmount` | `number` | `20.0` | Maximum blur radius in pixels
|
|
654
|
-
| `
|
|
655
|
-
| `
|
|
656
|
-
| `
|
|
657
|
-
| `
|
|
658
|
-
| `
|
|
659
|
-
| `
|
|
651
|
+
| Prop | Type | Default | Description |
|
|
652
|
+
| ---------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------- | --------------------------------------------------------------- |
|
|
653
|
+
| `blurType` | `BlurType` | `'regular'` | The type of blur effect to apply |
|
|
654
|
+
| `blurAmount` | `number` | `20.0` | Maximum blur radius in pixels |
|
|
655
|
+
| `blurRounds` | `number` | `5` | The number of blur interactions must be an integer value (1-15) |
|
|
656
|
+
| `direction` | `'blurredTopClearBottom' \| 'blurredBottomClearTop' \| 'blurredCenterClearTopAndBottom'` | `'blurredTopClearBottom'` | Direction of the blur gradient |
|
|
657
|
+
| `startOffset` | `number` | `0.0` | Where the gradient starts (0.0 to 1.0) |
|
|
658
|
+
| `reducedTransparencyFallbackColor` | `string` | `'#FFFFFF'` | Fallback color when reduced transparency is enabled |
|
|
659
|
+
| `overlayColor` | `ColorValue` | `undefined` | The overlay color to apply on top of the blur effect |
|
|
660
|
+
| `style` | `ViewStyle` | `undefined` | Style object for the blur view |
|
|
661
|
+
| `children` | `ReactNode` | `undefined` | Child components to render inside the blur view |
|
|
660
662
|
|
|
661
663
|
> **Platform Note**: `ProgressiveBlurView` works on both **iOS** and **Android**.
|
|
662
664
|
>
|
|
@@ -696,7 +698,8 @@ All props are optional and have sensible defaults.
|
|
|
696
698
|
| --------------- | ------------------------------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
697
699
|
| `value` | `boolean` | `false` | The current value of the switch |
|
|
698
700
|
| `onValueChange` | `(value: boolean) => void` | `undefined` | Callback invoked when the switch value changes |
|
|
699
|
-
| `blurAmount` | `number` | `10`
|
|
701
|
+
| `blurAmount` | `number` | `10.0` | (Android only) The intensity of the blur effect (0-100) |
|
|
702
|
+
| `blurRounds` | `number` | `5` | The number of blur interactions must be an integer value (1-15) |
|
|
700
703
|
| `thumbColor` | `ColorValue` | `'#FFFFFF'` | (iOS only) The color of the switch thumb |
|
|
701
704
|
| `trackColor` | `{ false?: ColorValue; true?: ColorValue }` | `{ false: '#E5E5EA', true: '#34C759' }` | Track colors. On Android, only `true` is used - QmBlurView auto-calculates on/off colors from base color |
|
|
702
705
|
| `disabled` | `boolean` | `false` | Whether the switch is disabled (prevents interaction but maintains current value) |
|
|
@@ -845,6 +848,7 @@ interface MyGlassContainerProps {
|
|
|
845
848
|
const blurProps: BlurViewProps = {
|
|
846
849
|
blurType: 'systemMaterial',
|
|
847
850
|
blurAmount: 50,
|
|
851
|
+
blurRounds: 10,
|
|
848
852
|
reducedTransparencyFallbackColor: '#FFFFFF',
|
|
849
853
|
overlayColor: '#FF000040',
|
|
850
854
|
};
|
|
@@ -867,6 +871,7 @@ const blurSwitchProps: BlurSwitchProps = {
|
|
|
867
871
|
value: true,
|
|
868
872
|
onValueChange: (value) => console.log(value),
|
|
869
873
|
blurAmount: 20,
|
|
874
|
+
blurRounds: 15,
|
|
870
875
|
trackColor: { true: '#34C759' },
|
|
871
876
|
disabled: false,
|
|
872
877
|
};
|
package/android/build.gradle
CHANGED
|
@@ -74,7 +74,7 @@ def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
|
74
74
|
dependencies {
|
|
75
75
|
implementation "com.facebook.react:react-android"
|
|
76
76
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
77
|
-
implementation 'com.qmdeve
|
|
77
|
+
implementation 'com.github.qmdeve:qmblurview:v1.1.5'
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
react {
|
|
@@ -2,37 +2,30 @@ package com.sbaiahmed1.reactnativeblur
|
|
|
2
2
|
|
|
3
3
|
import android.graphics.Color
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Enum representing different blur types with their corresponding overlay colors.
|
|
7
|
-
* Maps iOS blur types to Android overlay colors to approximate the visual appearance.
|
|
8
|
-
*/
|
|
9
5
|
enum class BlurType(val overlayColor: Int) {
|
|
10
6
|
XLIGHT(Color.argb(140, 240, 240, 240)),
|
|
11
7
|
LIGHT(Color.argb(42, 255, 255, 255)),
|
|
12
|
-
DARK(Color.argb(120,
|
|
8
|
+
DARK(Color.argb(120, 26, 22, 22)),
|
|
13
9
|
EXTRA_DARK(Color.argb(160, 35, 35, 35)),
|
|
14
10
|
REGULAR(Color.argb(35, 255, 255, 255)),
|
|
15
|
-
PROMINENT(Color.argb(
|
|
11
|
+
PROMINENT(Color.argb(140, 240, 240, 240)),
|
|
16
12
|
SYSTEM_ULTRA_THIN_MATERIAL(Color.argb(75, 240, 240, 240)),
|
|
17
|
-
SYSTEM_ULTRA_THIN_MATERIAL_LIGHT(Color.argb(
|
|
13
|
+
SYSTEM_ULTRA_THIN_MATERIAL_LIGHT(Color.argb(75, 240, 240, 240)),
|
|
18
14
|
SYSTEM_ULTRA_THIN_MATERIAL_DARK(Color.argb(65, 40, 40, 40)),
|
|
19
15
|
SYSTEM_THIN_MATERIAL(Color.argb(102, 240, 240, 240)),
|
|
20
|
-
SYSTEM_THIN_MATERIAL_LIGHT(Color.argb(
|
|
16
|
+
SYSTEM_THIN_MATERIAL_LIGHT(Color.argb(102, 240, 240, 240)),
|
|
21
17
|
SYSTEM_THIN_MATERIAL_DARK(Color.argb(102, 35, 35, 35)),
|
|
22
|
-
SYSTEM_MATERIAL(Color.argb(
|
|
23
|
-
SYSTEM_MATERIAL_LIGHT(Color.argb(
|
|
18
|
+
SYSTEM_MATERIAL(Color.argb(140, 245, 245, 245)),
|
|
19
|
+
SYSTEM_MATERIAL_LIGHT(Color.argb(140, 245, 245, 245)),
|
|
24
20
|
SYSTEM_MATERIAL_DARK(Color.argb(215, 65, 60, 60)),
|
|
25
|
-
SYSTEM_THICK_MATERIAL(Color.argb(
|
|
26
|
-
SYSTEM_THICK_MATERIAL_LIGHT(Color.argb(
|
|
21
|
+
SYSTEM_THICK_MATERIAL(Color.argb(210, 248, 248, 248)),
|
|
22
|
+
SYSTEM_THICK_MATERIAL_LIGHT(Color.argb(210, 248, 248, 248)),
|
|
27
23
|
SYSTEM_THICK_MATERIAL_DARK(Color.argb(160, 35, 35, 35)),
|
|
28
|
-
SYSTEM_CHROME_MATERIAL(Color.argb(
|
|
29
|
-
SYSTEM_CHROME_MATERIAL_LIGHT(Color.argb(
|
|
30
|
-
SYSTEM_CHROME_MATERIAL_DARK(Color.argb(
|
|
24
|
+
SYSTEM_CHROME_MATERIAL(Color.argb(165, 248, 248, 248)),
|
|
25
|
+
SYSTEM_CHROME_MATERIAL_LIGHT(Color.argb(165, 248, 248, 248)),
|
|
26
|
+
SYSTEM_CHROME_MATERIAL_DARK(Color.argb(100, 32, 32, 32));
|
|
31
27
|
|
|
32
28
|
companion object {
|
|
33
|
-
/**
|
|
34
|
-
* Get BlurType from string, with fallback to LIGHT for unknown types.
|
|
35
|
-
*/
|
|
36
29
|
fun fromString(type: String): BlurType {
|
|
37
30
|
return when (type.lowercase()) {
|
|
38
31
|
"xlight" -> XLIGHT
|
|
@@ -56,7 +49,7 @@ enum class BlurType(val overlayColor: Int) {
|
|
|
56
49
|
"systemchromematerial" -> SYSTEM_CHROME_MATERIAL
|
|
57
50
|
"systemchromemateriallight" -> SYSTEM_CHROME_MATERIAL_LIGHT
|
|
58
51
|
"systemchromematerialdark" -> SYSTEM_CHROME_MATERIAL_DARK
|
|
59
|
-
else -> XLIGHT
|
|
52
|
+
else -> XLIGHT
|
|
60
53
|
}
|
|
61
54
|
}
|
|
62
55
|
}
|
|
@@ -22,9 +22,11 @@ class ReactNativeBlurSwitch : BlurSwitchButtonView {
|
|
|
22
22
|
private var onValueChangeListener: ((Boolean) -> Unit)? = null
|
|
23
23
|
private var currentValue = false
|
|
24
24
|
private var isDisabled = false
|
|
25
|
+
private var currentBlurRounds = DEFAULT_BLUR_ROUNDS
|
|
25
26
|
|
|
26
27
|
companion object {
|
|
27
28
|
private const val TAG = "ReactNativeBlurSwitch"
|
|
29
|
+
private const val DEFAULT_BLUR_ROUNDS = 5
|
|
28
30
|
private const val DEFAULT_WIDTH_DP = 65f
|
|
29
31
|
private const val DEFAULT_HEIGHT_DP = 36f
|
|
30
32
|
private const val MIN_BLUR_AMOUNT = 0f
|
|
@@ -70,7 +72,7 @@ class ReactNativeBlurSwitch : BlurSwitchButtonView {
|
|
|
70
72
|
*/
|
|
71
73
|
private fun initializeSwitch() {
|
|
72
74
|
try {
|
|
73
|
-
blurRounds =
|
|
75
|
+
blurRounds = currentBlurRounds
|
|
74
76
|
|
|
75
77
|
setOnCheckedChangeListener { isChecked ->
|
|
76
78
|
if (isDisabled) {
|
|
@@ -172,6 +174,22 @@ class ReactNativeBlurSwitch : BlurSwitchButtonView {
|
|
|
172
174
|
}
|
|
173
175
|
}
|
|
174
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Set the number of blur rounds.
|
|
179
|
+
* @param rounds The number of blur rounds (1-15)
|
|
180
|
+
*/
|
|
181
|
+
fun setRounds(rounds: Int) {
|
|
182
|
+
val blurRounds = rounds.coerceIn(1, 15)
|
|
183
|
+
currentBlurRounds = blurRounds
|
|
184
|
+
logDebug("setRounds: $rounds -> $blurRounds")
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
super.setBlurRounds(blurRounds)
|
|
188
|
+
} catch (e: Exception) {
|
|
189
|
+
logError("Failed to set blur rounds: ${e.message}", e)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
175
193
|
/**
|
|
176
194
|
* Set whether the switch is disabled.
|
|
177
195
|
* @param disabled True to disable, false to enable
|
package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurSwitchManager.kt
CHANGED
|
@@ -40,6 +40,11 @@ class ReactNativeBlurSwitchManager : SimpleViewManager<ReactNativeBlurSwitch>()
|
|
|
40
40
|
view?.setBlurAmount(blurAmount.toFloat())
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
@ReactProp(name = "blurRounds")
|
|
44
|
+
fun setBlurRounds(view: ReactNativeBlurSwitch?, blurRounds: Int) {
|
|
45
|
+
view?.setRounds(blurRounds)
|
|
46
|
+
}
|
|
47
|
+
|
|
43
48
|
@ReactProp(name = "thumbColor")
|
|
44
49
|
fun setThumbColor(view: ReactNativeBlurSwitch?, color: String?) {
|
|
45
50
|
color?.let {
|
|
@@ -3,6 +3,8 @@ package com.sbaiahmed1.reactnativeblur
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.graphics.Color
|
|
5
5
|
import android.graphics.Outline
|
|
6
|
+
import android.graphics.Path
|
|
7
|
+
import android.os.Build
|
|
6
8
|
import android.util.AttributeSet
|
|
7
9
|
import android.util.Log
|
|
8
10
|
import android.util.TypedValue
|
|
@@ -30,11 +32,17 @@ import android.view.View.MeasureSpec
|
|
|
30
32
|
class ReactNativeBlurView : BlurViewGroup {
|
|
31
33
|
private var currentBlurRadius = DEFAULT_BLUR_RADIUS
|
|
32
34
|
private var currentOverlayColor = Color.TRANSPARENT
|
|
33
|
-
private var
|
|
35
|
+
private var currentBlurRounds = DEFAULT_BLUR_ROUNDS
|
|
36
|
+
private var borderRadius = 0f
|
|
37
|
+
private var borderTopLeftRadius = -1f
|
|
38
|
+
private var borderTopRightRadius = -1f
|
|
39
|
+
private var borderBottomLeftRadius = -1f
|
|
40
|
+
private var borderBottomRightRadius = -1f
|
|
34
41
|
private var glassTintColor: Int = Color.TRANSPARENT
|
|
35
42
|
private var glassOpacity: Float = 1.0f
|
|
36
43
|
private var viewType: String = "blur"
|
|
37
44
|
private var glassType: String = "clear"
|
|
45
|
+
private var currentBlurType: String = "xlight"
|
|
38
46
|
private var isBlurInitialized: Boolean = false
|
|
39
47
|
private var initRunnable: Runnable? = null
|
|
40
48
|
|
|
@@ -42,9 +50,9 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
42
50
|
private const val TAG = "ReactNativeBlurView"
|
|
43
51
|
private const val MAX_BLUR_RADIUS = 100f
|
|
44
52
|
private const val DEFAULT_BLUR_RADIUS = 10f
|
|
53
|
+
private const val DEFAULT_BLUR_ROUNDS = 5
|
|
45
54
|
private const val DEBUG = false
|
|
46
55
|
|
|
47
|
-
// Cross-platform blur amount constants
|
|
48
56
|
private const val MIN_BLUR_AMOUNT = 0f
|
|
49
57
|
private const val MAX_BLUR_AMOUNT = 100f
|
|
50
58
|
|
|
@@ -62,12 +70,6 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
62
70
|
Log.e(TAG, message, throwable)
|
|
63
71
|
}
|
|
64
72
|
|
|
65
|
-
/**
|
|
66
|
-
* Maps blur amount (0-100) to Android blur radius (0-25).
|
|
67
|
-
* This ensures cross-platform consistency while respecting Android's limitations.
|
|
68
|
-
* @param amount The blur amount from 0-100
|
|
69
|
-
* @return The corresponding blur radius from 0-25
|
|
70
|
-
*/
|
|
71
73
|
private fun mapBlurAmountToRadius(amount: Float): Float {
|
|
72
74
|
val clampedAmount = amount.coerceIn(MIN_BLUR_AMOUNT, MAX_BLUR_AMOUNT)
|
|
73
75
|
return (clampedAmount / MAX_BLUR_AMOUNT) * MAX_BLUR_RADIUS
|
|
@@ -82,58 +84,32 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
82
84
|
setupView()
|
|
83
85
|
}
|
|
84
86
|
|
|
85
|
-
/**
|
|
86
|
-
* Initial view setup in constructor - only sets up visual defaults.
|
|
87
|
-
* Blur initialization is deferred to onAttachedToWindow to ensure the
|
|
88
|
-
* view hierarchy is fully mounted, preventing flickering and wrong frame capture.
|
|
89
|
-
*/
|
|
90
87
|
private fun setupView() {
|
|
91
88
|
super.setBackgroundColor(currentOverlayColor)
|
|
92
89
|
clipChildren = true
|
|
93
90
|
clipToOutline = true
|
|
94
|
-
blurRounds =
|
|
91
|
+
blurRounds = currentBlurRounds
|
|
95
92
|
super.setDownsampleFactor(6.0F)
|
|
96
93
|
}
|
|
97
94
|
|
|
98
|
-
/**
|
|
99
|
-
* Called when the view is attached to a window.
|
|
100
|
-
* After QmBlurView's onAttachedToWindow sets the decor view as blur root,
|
|
101
|
-
* we use reflection to redirect it to the nearest Screen ancestor.
|
|
102
|
-
* This scopes the blur capture to just the current screen, preventing
|
|
103
|
-
* navigation transition artifacts.
|
|
104
|
-
*/
|
|
105
95
|
override fun onAttachedToWindow() {
|
|
106
96
|
super.onAttachedToWindow()
|
|
107
97
|
|
|
108
98
|
if (isBlurInitialized) return
|
|
109
99
|
|
|
110
|
-
// Immediately try to swap blur root and initialize.
|
|
111
|
-
// We avoid posting a runnable to prevent the 1-second delay artifact.
|
|
112
|
-
// If the parent hierarchy is not ready yet (unlikely in onAttachedToWindow),
|
|
113
|
-
// we could fall back to post, but for now we prioritize immediate execution.
|
|
114
100
|
swapBlurRootToScreenAncestor()
|
|
115
101
|
initializeBlur()
|
|
116
102
|
}
|
|
117
103
|
|
|
118
|
-
/**
|
|
119
|
-
* Uses reflection to redirect QmBlurView's internal blur capture root
|
|
120
|
-
* from the activity decor view to the nearest react-native-screens Screen ancestor.
|
|
121
|
-
*
|
|
122
|
-
* Reflection path: BlurViewGroup.mBaseBlurViewGroup -> BaseBlurViewGroup.mDecorView
|
|
123
|
-
* Also moves the OnPreDrawListener from the old root to the new one.
|
|
124
|
-
*/
|
|
125
104
|
private fun swapBlurRootToScreenAncestor() {
|
|
126
|
-
// Pinned to QmBlurView 1.1.4 – depends on: mBaseBlurViewGroup, mDecorView, preDrawListener, mDifferentRoot, mForceRedraw
|
|
127
105
|
val newRoot = findOptimalBlurRoot() ?: return
|
|
128
106
|
|
|
129
107
|
try {
|
|
130
|
-
// Step 1: Get BlurViewGroup's private mBaseBlurViewGroup field
|
|
131
108
|
val blurViewGroupClass = BlurViewGroup::class.java
|
|
132
109
|
val baseField = blurViewGroupClass.getDeclaredField("mBaseBlurViewGroup")
|
|
133
110
|
baseField.isAccessible = true
|
|
134
111
|
val baseBlurViewGroup = baseField.get(this) ?: return
|
|
135
112
|
|
|
136
|
-
// Step 2: Get BaseBlurViewGroup's private fields
|
|
137
113
|
val baseClass = BaseBlurViewGroup::class.java
|
|
138
114
|
|
|
139
115
|
val decorViewField = baseClass.getDeclaredField("mDecorView")
|
|
@@ -152,25 +128,20 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
152
128
|
}
|
|
153
129
|
|
|
154
130
|
if (preDrawListener != null && oldDecorView != null) {
|
|
155
|
-
// Step 3: Remove listener from old root's ViewTreeObserver
|
|
156
131
|
try {
|
|
157
132
|
oldDecorView.viewTreeObserver.removeOnPreDrawListener(preDrawListener)
|
|
158
133
|
} catch (e: Exception) {
|
|
159
134
|
logDebug("Could not remove old pre-draw listener: ${e.message}")
|
|
160
135
|
}
|
|
161
136
|
|
|
162
|
-
// Step 4: Set new root as mDecorView
|
|
163
137
|
decorViewField.set(baseBlurViewGroup, newRoot)
|
|
164
138
|
|
|
165
|
-
// Step 5: Add listener to new root's ViewTreeObserver
|
|
166
139
|
newRoot.viewTreeObserver.addOnPreDrawListener(preDrawListener)
|
|
167
140
|
|
|
168
|
-
// Step 6: Update mDifferentRoot flag
|
|
169
141
|
val differentRootField = baseClass.getDeclaredField("mDifferentRoot")
|
|
170
142
|
differentRootField.isAccessible = true
|
|
171
143
|
differentRootField.setBoolean(baseBlurViewGroup, newRoot.rootView != this.rootView)
|
|
172
144
|
|
|
173
|
-
// Step 7: Force a redraw
|
|
174
145
|
val forceRedrawField = baseClass.getDeclaredField("mForceRedraw")
|
|
175
146
|
forceRedrawField.isAccessible = true
|
|
176
147
|
forceRedrawField.setBoolean(baseBlurViewGroup, true)
|
|
@@ -184,27 +155,10 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
184
155
|
}
|
|
185
156
|
}
|
|
186
157
|
|
|
187
|
-
/**
|
|
188
|
-
* Finds the optimal view to use as blur capture root.
|
|
189
|
-
*
|
|
190
|
-
* Priority:
|
|
191
|
-
* 1. Nearest react-native-screens Screen ancestor — scopes blur to the current
|
|
192
|
-
* screen and prevents capturing navigation transition artifacts.
|
|
193
|
-
* 2. Nearest ReactRootView ancestor — scopes blur to the React Native root when
|
|
194
|
-
* the component is not inside a Screen (e.g. plain View hierarchies). Without
|
|
195
|
-
* this fallback, QmBlurView defaults to the activity decor view and blurs the
|
|
196
|
-
* entire screen instead of just the component area (issue #89).
|
|
197
|
-
* 3. null — returned for modals, which intentionally need to blur content from
|
|
198
|
-
* the main activity window (decor view is correct there).
|
|
199
|
-
*/
|
|
200
158
|
private fun findOptimalBlurRoot(): ViewGroup? {
|
|
201
159
|
return findNearestScreenAncestor() ?: findNearestReactRootView()
|
|
202
160
|
}
|
|
203
161
|
|
|
204
|
-
/**
|
|
205
|
-
* Walks up the view hierarchy looking for react-native-screens Screen components
|
|
206
|
-
* using class name detection to avoid hard dependencies on react-native-screens.
|
|
207
|
-
*/
|
|
208
162
|
private fun findNearestScreenAncestor(): ViewGroup? {
|
|
209
163
|
var currentParent = this.parent
|
|
210
164
|
while (currentParent != null) {
|
|
@@ -216,11 +170,6 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
216
170
|
return null
|
|
217
171
|
}
|
|
218
172
|
|
|
219
|
-
/**
|
|
220
|
-
* Walks up the view hierarchy looking for the React Native root view.
|
|
221
|
-
* Used as a fallback when no Screen ancestor exists, to scope the blur
|
|
222
|
-
* capture to the RN root rather than the full activity decor view.
|
|
223
|
-
*/
|
|
224
173
|
private fun findNearestReactRootView(): ViewGroup? {
|
|
225
174
|
var currentParent = this.parent
|
|
226
175
|
while (currentParent != null) {
|
|
@@ -232,11 +181,6 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
232
181
|
return null
|
|
233
182
|
}
|
|
234
183
|
|
|
235
|
-
/**
|
|
236
|
-
* Initialize the blur view with current settings.
|
|
237
|
-
* Called after the view is attached and the blur root has been swapped.
|
|
238
|
-
* Guarded by isBlurInitialized to prevent duplicate setup.
|
|
239
|
-
*/
|
|
240
184
|
private fun initializeBlur() {
|
|
241
185
|
if (isBlurInitialized) return
|
|
242
186
|
|
|
@@ -252,20 +196,11 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
252
196
|
}
|
|
253
197
|
}
|
|
254
198
|
|
|
255
|
-
/**
|
|
256
|
-
* Called when the view is detached from a window.
|
|
257
|
-
* Performs cleanup to prevent memory leaks and resets initialization state
|
|
258
|
-
* so blur is re-initialized on next attach (e.g. navigation transitions).
|
|
259
|
-
*/
|
|
260
199
|
override fun onDetachedFromWindow() {
|
|
261
200
|
super.onDetachedFromWindow()
|
|
262
201
|
cleanup()
|
|
263
202
|
}
|
|
264
203
|
|
|
265
|
-
/**
|
|
266
|
-
* Cleanup method to reset state.
|
|
267
|
-
* Helps prevent memory leaks and ensures clean state.
|
|
268
|
-
*/
|
|
269
204
|
fun cleanup() {
|
|
270
205
|
isBlurInitialized = false
|
|
271
206
|
initRunnable?.let { removeCallbacks(it) }
|
|
@@ -273,10 +208,6 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
273
208
|
logDebug("View cleaned up")
|
|
274
209
|
}
|
|
275
210
|
|
|
276
|
-
/**
|
|
277
|
-
* Set the blur amount with cross-platform mapping.
|
|
278
|
-
* @param amount The blur amount value (0-100), will be mapped to Android's 0-25 radius range
|
|
279
|
-
*/
|
|
280
211
|
fun setBlurAmount(amount: Float) {
|
|
281
212
|
currentBlurRadius = mapBlurAmountToRadius(amount)
|
|
282
213
|
logDebug("setBlurAmount: $amount -> $currentBlurRadius (mapped from 0-100 to 0-25 range)")
|
|
@@ -288,11 +219,24 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
288
219
|
}
|
|
289
220
|
}
|
|
290
221
|
|
|
222
|
+
fun setRounds(rounds: Int) {
|
|
223
|
+
val blurRounds = rounds.coerceIn(1, 15)
|
|
224
|
+
currentBlurRounds = blurRounds
|
|
225
|
+
logDebug("setRounds: $rounds -> $blurRounds")
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
super.setBlurRounds(blurRounds)
|
|
229
|
+
} catch (e: Exception) {
|
|
230
|
+
logError("Failed to set blur rounds: ${e.message}", e)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
291
234
|
/**
|
|
292
235
|
* Set the blur type which determines the overlay color.
|
|
293
236
|
* @param type The blur type string (case-insensitive)
|
|
294
237
|
*/
|
|
295
238
|
fun setBlurType(type: String) {
|
|
239
|
+
currentBlurType = type
|
|
296
240
|
val blurType = BlurType.fromString(type)
|
|
297
241
|
currentOverlayColor = blurType.overlayColor
|
|
298
242
|
logDebug("setBlurType: $type -> ${blurType.name}")
|
|
@@ -307,9 +251,6 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
307
251
|
|
|
308
252
|
/**
|
|
309
253
|
* Set the glass tint color for liquid glass effect.
|
|
310
|
-
* @param color The color string in hex format (e.g., "#FF0000") or null to clear
|
|
311
|
-
*/
|
|
312
|
-
fun setGlassTintColor(color: String?) {
|
|
313
254
|
color?.let {
|
|
314
255
|
try {
|
|
315
256
|
glassTintColor = it.toColorInt()
|
|
@@ -326,58 +267,37 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
326
267
|
}
|
|
327
268
|
}
|
|
328
269
|
|
|
329
|
-
/**
|
|
330
|
-
* Set the glass opacity for liquid glass effect.
|
|
331
|
-
* @param opacity The opacity value (0.0 to 1.0)
|
|
332
|
-
*/
|
|
333
270
|
fun setGlassOpacity(opacity: Float) {
|
|
334
271
|
glassOpacity = opacity.coerceIn(0.0f, 1.0f)
|
|
335
272
|
logDebug("setGlassOpacity: $opacity")
|
|
336
273
|
updateGlassEffect()
|
|
337
274
|
}
|
|
338
275
|
|
|
339
|
-
/**
|
|
340
|
-
* Set the view type (blur or liquidGlass).
|
|
341
|
-
* @param type The view type string
|
|
342
|
-
*/
|
|
343
276
|
fun setType(type: String) {
|
|
344
277
|
viewType = type
|
|
345
278
|
logDebug("setType: $type")
|
|
346
279
|
updateViewType()
|
|
347
280
|
}
|
|
348
281
|
|
|
349
|
-
/**
|
|
350
|
-
* Set the view type (blur or liquidGlass).
|
|
351
|
-
* @param isInteractive The view type string
|
|
352
|
-
*/
|
|
353
282
|
fun setIsInteractive(isInteractive: Boolean) {
|
|
354
283
|
logDebug("setType: $isInteractive")
|
|
355
284
|
}
|
|
356
285
|
|
|
357
|
-
/**
|
|
358
|
-
* Set the glass type for liquid glass effect.
|
|
359
|
-
* @param type The glass type string
|
|
360
|
-
*/
|
|
361
286
|
fun setGlassType(type: String) {
|
|
362
287
|
glassType = type
|
|
363
288
|
logDebug("setGlassType: $type")
|
|
364
289
|
updateGlassEffect()
|
|
365
290
|
}
|
|
366
291
|
|
|
367
|
-
/**
|
|
368
|
-
* Update the glass effect based on current glass properties.
|
|
369
|
-
*/
|
|
370
292
|
private fun updateGlassEffect() {
|
|
371
293
|
if (viewType == "liquidGlass") {
|
|
372
294
|
try {
|
|
373
|
-
// Apply glass tint with opacity
|
|
374
295
|
val glassColor = Color.argb(
|
|
375
296
|
(glassOpacity * 255).toInt(),
|
|
376
297
|
Color.red(glassTintColor),
|
|
377
298
|
Color.green(glassTintColor),
|
|
378
299
|
Color.blue(glassTintColor)
|
|
379
300
|
)
|
|
380
|
-
// Use QmBlurView's setOverlayColor method
|
|
381
301
|
super.setOverlayColor(glassColor)
|
|
382
302
|
logDebug("Applied glass effect: color=$glassColor, opacity=$glassOpacity")
|
|
383
303
|
} catch (e: Exception) {
|
|
@@ -386,16 +306,12 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
386
306
|
}
|
|
387
307
|
}
|
|
388
308
|
|
|
389
|
-
/**
|
|
390
|
-
* Update the view type and apply appropriate effects.
|
|
391
|
-
*/
|
|
392
309
|
private fun updateViewType() {
|
|
393
310
|
when (viewType) {
|
|
394
311
|
"liquidGlass" -> {
|
|
395
312
|
updateGlassEffect()
|
|
396
313
|
}
|
|
397
314
|
"blur" -> {
|
|
398
|
-
// Restore original blur overlay color
|
|
399
315
|
try {
|
|
400
316
|
super.setBackgroundColor(currentOverlayColor)
|
|
401
317
|
super.setOverlayColor(currentOverlayColor)
|
|
@@ -406,40 +322,90 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
406
322
|
}
|
|
407
323
|
}
|
|
408
324
|
|
|
409
|
-
/**
|
|
410
|
-
* Set the border radius from React Native StyleSheet.
|
|
411
|
-
* React Native provides values in logical pixels (dp), which we convert for the native view.
|
|
412
|
-
* @param radius The border radius value in dp
|
|
413
|
-
*/
|
|
414
325
|
fun setBorderRadius(radius: Float) {
|
|
415
|
-
|
|
326
|
+
borderRadius = radius
|
|
416
327
|
logDebug("setBorderRadius: $radius dp")
|
|
417
328
|
updateCornerRadius()
|
|
418
329
|
}
|
|
419
330
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
331
|
+
fun setBorderTopLeftRadius(radius: Float) {
|
|
332
|
+
borderTopLeftRadius = radius
|
|
333
|
+
logDebug("setBorderTopLeftRadius: $radius dp")
|
|
334
|
+
updateCornerRadius()
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
fun setBorderTopRightRadius(radius: Float) {
|
|
338
|
+
borderTopRightRadius = radius
|
|
339
|
+
logDebug("setBorderTopRightRadius: $radius dp")
|
|
340
|
+
updateCornerRadius()
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
fun setBorderBottomLeftRadius(radius: Float) {
|
|
344
|
+
borderBottomLeftRadius = radius
|
|
345
|
+
logDebug("setBorderBottomLeftRadius: $radius dp")
|
|
346
|
+
updateCornerRadius()
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
fun setBorderBottomRightRadius(radius: Float) {
|
|
350
|
+
borderBottomRightRadius = radius
|
|
351
|
+
logDebug("setBorderBottomRightRadius: $radius dp")
|
|
352
|
+
updateCornerRadius()
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
private fun convertDpToPx(dp: Float): Float {
|
|
356
|
+
val displayMetrics = context.resources.displayMetrics
|
|
357
|
+
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics)
|
|
358
|
+
}
|
|
359
|
+
|
|
425
360
|
private fun updateCornerRadius() {
|
|
426
361
|
try {
|
|
427
|
-
|
|
428
|
-
val
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
362
|
+
val baseRadius = convertDpToPx(borderRadius)
|
|
363
|
+
val topLeft = if (borderTopLeftRadius > 0) convertDpToPx(borderTopLeftRadius) else baseRadius
|
|
364
|
+
val topRight = if (borderTopRightRadius > 0) convertDpToPx(borderTopRightRadius) else baseRadius
|
|
365
|
+
val bottomLeft = if (borderBottomLeftRadius > 0) convertDpToPx(borderBottomLeftRadius) else baseRadius
|
|
366
|
+
val bottomRight = if (borderBottomRightRadius > 0) convertDpToPx(borderBottomRightRadius) else baseRadius
|
|
367
|
+
|
|
368
|
+
super.setTopLeftCornerRadius(topLeft)
|
|
369
|
+
super.setTopRightCornerRadius(topRight)
|
|
370
|
+
super.setBottomLeftCornerRadius(bottomLeft)
|
|
371
|
+
super.setBottomRightCornerRadius(bottomRight)
|
|
372
|
+
super.setCornerRadius(baseRadius)
|
|
373
|
+
|
|
374
|
+
val isUniform = topLeft == topRight && topRight == bottomLeft && bottomLeft == bottomRight
|
|
375
|
+
|
|
376
|
+
if (isUniform) {
|
|
377
|
+
outlineProvider = object : ViewOutlineProvider() {
|
|
378
|
+
override fun getOutline(view: View, outline: Outline?) {
|
|
379
|
+
outline?.setRoundRect(0, 0, view.width, view.height, baseRadius)
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
outlineProvider = object : ViewOutlineProvider() {
|
|
384
|
+
override fun getOutline(view: View, outline: Outline?) {
|
|
385
|
+
val path = Path()
|
|
386
|
+
val radii = floatArrayOf(
|
|
387
|
+
topLeft,
|
|
388
|
+
topLeft,
|
|
389
|
+
topRight,
|
|
390
|
+
topRight,
|
|
391
|
+
bottomRight,
|
|
392
|
+
bottomRight,
|
|
393
|
+
bottomLeft,
|
|
394
|
+
bottomLeft
|
|
395
|
+
)
|
|
396
|
+
path.addRoundRect(0f, 0f, view.width.toFloat(), view.height.toFloat(), radii, Path.Direction.CW)
|
|
397
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
398
|
+
outline?.setPath(path)
|
|
399
|
+
} else {
|
|
400
|
+
@Suppress("DEPRECATION")
|
|
401
|
+
outline?.setConvexPath(path)
|
|
402
|
+
}
|
|
403
|
+
}
|
|
437
404
|
}
|
|
438
405
|
}
|
|
439
|
-
clipToOutline = true
|
|
440
406
|
|
|
441
|
-
|
|
442
|
-
logDebug("Updated corner radius:
|
|
407
|
+
clipToOutline = true
|
|
408
|
+
logDebug("Updated corner radius: topLeft=$topLeft, topRight=$topRight, bottomLeft=$bottomLeft, bottomRight=$bottomRight (px)")
|
|
443
409
|
} catch (e: Exception) {
|
|
444
410
|
logError("Failed to update corner radius: ${e.message}", e)
|
|
445
411
|
}
|
|
@@ -474,8 +440,5 @@ class ReactNativeBlurView : BlurViewGroup {
|
|
|
474
440
|
*/
|
|
475
441
|
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
476
442
|
// No-op: Layout is handled by React Native's UIManager.
|
|
477
|
-
// We override this to prevent the superclass (BlurViewGroup/FrameLayout) from
|
|
478
|
-
// re-positioning children based on its own logic (e.g. gravity), which would
|
|
479
|
-
// conflict with React Native's layout.
|
|
480
443
|
}
|
|
481
444
|
}
|