@sbaiahmed1/react-native-blur 3.0.0-beta.1 → 3.1.1
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 +209 -107
- package/ReactNativeBlur.podspec +1 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ComponentDescriptors.cpp +0 -1
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ComponentDescriptors.h +0 -1
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/EventEmitters.cpp +0 -1
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/EventEmitters.h +0 -7
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/Props.cpp +0 -9
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/Props.h +0 -28
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ShadowNodes.cpp +0 -1
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ShadowNodes.h +0 -11
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/States.h +0 -12
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurView.kt +46 -5
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurViewManager.kt +10 -0
- package/ios/Helpers/BlurStyleHelpers.swift +59 -0
- package/ios/Helpers/ReactNativeBlurViewHelper.swift +59 -0
- package/ios/ReactNativeBlurView.mm +6 -1
- package/ios/ReactNativeBlurViewManager.m +6 -0
- package/ios/Views/AdvancedBlurView.swift +135 -0
- package/ios/Views/BasicColoredView.swift +58 -0
- package/ios/Views/BlurEffectView.swift +72 -0
- package/package.json +1 -1
- 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/ios/ReactNativeBlurView.swift +0 -321
|
@@ -19,6 +19,7 @@ class ReactNativeBlurView : BlurView {
|
|
|
19
19
|
private var blurRadius = mapBlurAmountToRadius(DEFAULT_BLUR_AMOUNT)
|
|
20
20
|
private var overlayColor = Color.TRANSPARENT
|
|
21
21
|
private var isSetup = false
|
|
22
|
+
private var isConfigured = false
|
|
22
23
|
private var pendingStyleUpdate: Boolean = false
|
|
23
24
|
private var originalBackgroundColor: Int? = null
|
|
24
25
|
private var hasExplicitBackground: Boolean = false
|
|
@@ -179,15 +180,23 @@ class ReactNativeBlurView : BlurView {
|
|
|
179
180
|
*/
|
|
180
181
|
override fun onAttachedToWindow() {
|
|
181
182
|
super.onAttachedToWindow()
|
|
182
|
-
|
|
183
|
+
|
|
184
|
+
// Now we can safely walk the parent hierarchy
|
|
185
|
+
if (!this.isConfigured) {
|
|
186
|
+
this.isConfigured = true
|
|
187
|
+
setupBlurView()
|
|
188
|
+
}
|
|
183
189
|
}
|
|
184
190
|
|
|
185
191
|
/**
|
|
186
192
|
* Called when the view is detached from a window.
|
|
187
|
-
* Performs cleanup to prevent memory leaks.
|
|
193
|
+
* Performs cleanup to prevent memory leaks and navigation transition issues.
|
|
188
194
|
*/
|
|
189
195
|
override fun onDetachedFromWindow() {
|
|
190
196
|
super.onDetachedFromWindow()
|
|
197
|
+
|
|
198
|
+
this.isConfigured = false
|
|
199
|
+
this.removeCallbacks(null)
|
|
191
200
|
cleanup()
|
|
192
201
|
}
|
|
193
202
|
|
|
@@ -195,7 +204,7 @@ class ReactNativeBlurView : BlurView {
|
|
|
195
204
|
* Cleanup method to reset state and remove pending callbacks.
|
|
196
205
|
* Helps prevent memory leaks and ensures clean state.
|
|
197
206
|
*/
|
|
198
|
-
|
|
207
|
+
fun cleanup() {
|
|
199
208
|
isSetup = false
|
|
200
209
|
hasExplicitBackground = false
|
|
201
210
|
originalBackgroundColor = null
|
|
@@ -213,7 +222,7 @@ class ReactNativeBlurView : BlurView {
|
|
|
213
222
|
if (isSetup) return
|
|
214
223
|
|
|
215
224
|
try {
|
|
216
|
-
val rootView =
|
|
225
|
+
val rootView = findOptimalBlurRoot()
|
|
217
226
|
|
|
218
227
|
rootView?.let { root ->
|
|
219
228
|
try {
|
|
@@ -261,12 +270,44 @@ class ReactNativeBlurView : BlurView {
|
|
|
261
270
|
isSetup = true
|
|
262
271
|
}
|
|
263
272
|
} catch (e: Exception) {
|
|
264
|
-
//
|
|
273
|
+
// Final fallback: set transparent background to prevent visual artifacts
|
|
265
274
|
super.setBackgroundColor(overlayColor)
|
|
266
275
|
logError("Failed to setup blur: ${e.message}", e)
|
|
267
276
|
}
|
|
268
277
|
}
|
|
269
278
|
|
|
279
|
+
/**
|
|
280
|
+
* Find the optimal blur root view by walking up the parent hierarchy.
|
|
281
|
+
* This method is crucial for proper blur rendering during navigation transitions.
|
|
282
|
+
* @return The optimal ViewGroup to use as blur root or null if not found
|
|
283
|
+
*/
|
|
284
|
+
private fun findOptimalBlurRoot(): ViewGroup? {
|
|
285
|
+
var current = this.parent
|
|
286
|
+
|
|
287
|
+
// Walk up the parent hierarchy to find the best blur root
|
|
288
|
+
while (current != null) {
|
|
289
|
+
if (current is ViewGroup) {
|
|
290
|
+
// Prefer content view as it's the most stable during transitions
|
|
291
|
+
if (current.id == android.R.id.content) {
|
|
292
|
+
return current
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Look for other suitable container views
|
|
296
|
+
val className = current.javaClass.simpleName
|
|
297
|
+
if (className.contains("DecorView") ||
|
|
298
|
+
className.contains("ContentFrameLayout") ||
|
|
299
|
+
(className.contains("LinearLayout") && current.parent == null)) {
|
|
300
|
+
// For LinearLayout, only consider it if it's the root of the hierarchy (parent == null)
|
|
301
|
+
// This avoids misidentifying containers in complex layouts
|
|
302
|
+
return current
|
|
303
|
+
}
|
|
304
|
+
current = current.parent
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Fallback: try to get activity's content view
|
|
308
|
+
return findRootView()
|
|
309
|
+
}
|
|
310
|
+
|
|
270
311
|
/**
|
|
271
312
|
* Find the root view using multiple strategies.
|
|
272
313
|
* @return The root ViewGroup or null if not found
|
|
@@ -69,6 +69,16 @@ class ReactNativeBlurViewManager : ViewGroupManager<ReactNativeBlurView>(),
|
|
|
69
69
|
view?.setIsInteractive(isInteractive)
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Called when view is detached from view hierarchy and allows for cleanup.
|
|
74
|
+
* This prevents the white screen issue during navigation transitions on Android.
|
|
75
|
+
*/
|
|
76
|
+
override fun onDropViewInstance(view: ReactNativeBlurView) {
|
|
77
|
+
super.onDropViewInstance(view)
|
|
78
|
+
// Call cleanup to reset state and prevent white screen artifacts
|
|
79
|
+
view.cleanup()
|
|
80
|
+
}
|
|
81
|
+
|
|
72
82
|
companion object {
|
|
73
83
|
const val NAME = "ReactNativeBlurView"
|
|
74
84
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// BlurStyleHelpers.swift
|
|
2
|
+
|
|
3
|
+
import SwiftUI
|
|
4
|
+
import UIKit
|
|
5
|
+
|
|
6
|
+
// MARK: - Style Mapping Helper Functions
|
|
7
|
+
|
|
8
|
+
/// Maps string blur style names to UIBlurEffect.Style values
|
|
9
|
+
func blurStyleFromString(_ styleString: String) -> UIBlurEffect.Style {
|
|
10
|
+
switch styleString {
|
|
11
|
+
case "xlight":
|
|
12
|
+
return .extraLight
|
|
13
|
+
case "light":
|
|
14
|
+
return .light
|
|
15
|
+
case "dark":
|
|
16
|
+
return .dark
|
|
17
|
+
case "extraDark":
|
|
18
|
+
return .systemThickMaterialDark
|
|
19
|
+
case "regular":
|
|
20
|
+
return .regular
|
|
21
|
+
case "prominent":
|
|
22
|
+
return .prominent
|
|
23
|
+
case "systemUltraThinMaterial":
|
|
24
|
+
return .systemUltraThinMaterial
|
|
25
|
+
case "systemThinMaterial":
|
|
26
|
+
return .systemThinMaterial
|
|
27
|
+
case "systemMaterial":
|
|
28
|
+
return .systemMaterial
|
|
29
|
+
case "systemThickMaterial":
|
|
30
|
+
return .systemThickMaterial
|
|
31
|
+
case "systemChromeMaterial":
|
|
32
|
+
return .systemChromeMaterial
|
|
33
|
+
default:
|
|
34
|
+
return .extraLight
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// Maps string glass type names to Glass effect values (iOS 26.0+)
|
|
39
|
+
@available(iOS 26.0, *)
|
|
40
|
+
func glassEffectFromString(_ glassTypeString: String) -> Glass {
|
|
41
|
+
switch glassTypeString {
|
|
42
|
+
case "regular":
|
|
43
|
+
return .regular
|
|
44
|
+
case "clear":
|
|
45
|
+
return .clear
|
|
46
|
+
default:
|
|
47
|
+
return .clear
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// MARK: - Blur Amount Mapping
|
|
52
|
+
|
|
53
|
+
/// Maps blur amount (0-100) to proper blur intensity using UIViewPropertyAnimator approach
|
|
54
|
+
func mapBlurAmountToIntensity(_ amount: Double) -> Double {
|
|
55
|
+
let clampedAmount = max(0.0, min(100.0, amount))
|
|
56
|
+
|
|
57
|
+
// Map 0-100 to 0-1.0 intensity for smooth progression
|
|
58
|
+
return clampedAmount / 100.0
|
|
59
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// ReactNativeBlurViewHelper.swift
|
|
2
|
+
|
|
3
|
+
import SwiftUI
|
|
4
|
+
import UIKit
|
|
5
|
+
|
|
6
|
+
// MARK: - Objective-C Bridging Helpers
|
|
7
|
+
|
|
8
|
+
@objc public class ReactNativeBlurViewHelper: NSObject {
|
|
9
|
+
|
|
10
|
+
/// Creates and returns a view containing a colored rectangle.
|
|
11
|
+
@objc public static func createBlurViewWithFrame(_ frame: CGRect) -> AdvancedBlurView {
|
|
12
|
+
return AdvancedBlurView(frame: frame)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/// Updates the blur view with a new glass tint color.
|
|
16
|
+
@objc public static func updateBlurView(_ blurView: AdvancedBlurView, withGlassTintColor glassTintColor: UIColor) {
|
|
17
|
+
blurView.glassTintColor = glassTintColor
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/// Updates the blur view with a new glass opacity.
|
|
21
|
+
@objc public static func updateBlurView(_ blurView: AdvancedBlurView, withGlassOpacity glassOpacity: Double) {
|
|
22
|
+
blurView.glassOpacity = glassOpacity
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/// Updates the blur view with a new blur amount.
|
|
26
|
+
@objc public static func updateBlurView(_ blurView: AdvancedBlurView, withBlurAmount blurAmount: Double) {
|
|
27
|
+
blurView.blurAmount = blurAmount
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// Updates the blur view with a new blur type.
|
|
31
|
+
@objc public static func updateBlurView(_ blurView: AdvancedBlurView, withBlurType blurType: String) {
|
|
32
|
+
blurView.blurTypeString = blurType
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Updates the blur view with a new glass type.
|
|
36
|
+
@objc public static func updateBlurView(_ blurView: AdvancedBlurView, withGlassType glassType: String) {
|
|
37
|
+
blurView.glassType = glassType
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/// Updates the blur view with a new blur style.
|
|
41
|
+
@objc public static func updateBlurView(_ blurView: AdvancedBlurView, withType type: String) {
|
|
42
|
+
blurView.type = type
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// Updates the blur view with a new blur style.
|
|
46
|
+
@objc public static func updateBlurView(_ blurView: AdvancedBlurView, withIsInteractive isInteractive: Bool) {
|
|
47
|
+
blurView.isInteractive = isInteractive
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// Updates the blur view with a new reduced transparency fallback color.
|
|
51
|
+
@objc public static func updateBlurView(_ blurView: AdvancedBlurView, withReducedTransparencyFallbackColor fallbackColor: UIColor) {
|
|
52
|
+
blurView.reducedTransparencyFallbackColor = fallbackColor
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/// No-op updater kept for API compatibility.
|
|
56
|
+
@objc public static func updateBlurView(_ blurView: AdvancedBlurView) {
|
|
57
|
+
// Nothing to update in the minimal implementation
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
#import <react/renderer/components/ReactNativeBlurViewSpec/RCTComponentViewHelpers.h>
|
|
7
7
|
|
|
8
8
|
#import "RCTFabricComponentsPlugins.h"
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
#if __has_include("ReactNativeBlur-Swift.h")
|
|
11
|
+
#import "ReactNativeBlur-Swift.h"
|
|
12
|
+
#else
|
|
13
|
+
#import <ReactNativeBlur/ReactNativeBlur-Swift.h>
|
|
14
|
+
#endif
|
|
10
15
|
|
|
11
16
|
using namespace facebook::react;
|
|
12
17
|
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
#import "ReactNativeBlurViewManager.h"
|
|
2
|
+
|
|
3
|
+
#if __has_include("ReactNativeBlur-Swift.h")
|
|
2
4
|
#import "ReactNativeBlur-Swift.h"
|
|
5
|
+
#else
|
|
6
|
+
#import <ReactNativeBlur/ReactNativeBlur-Swift.h>
|
|
7
|
+
#endif
|
|
8
|
+
|
|
3
9
|
#import <React/RCTUIManager.h>
|
|
4
10
|
#import <React/RCTBridge.h>
|
|
5
11
|
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
// MARK: - UIKit Wrapper
|
|
5
|
+
|
|
6
|
+
@objc public class AdvancedBlurView: UIView {
|
|
7
|
+
|
|
8
|
+
private var hostingController: UIHostingController<BasicColoredView>?
|
|
9
|
+
|
|
10
|
+
@objc public var glassTintColor: UIColor = .clear {
|
|
11
|
+
didSet {
|
|
12
|
+
updateView()
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@objc public var glassOpacity: Double = 1.0 {
|
|
17
|
+
didSet {
|
|
18
|
+
updateView()
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@objc public var blurAmount: Double = 10.0 {
|
|
23
|
+
didSet {
|
|
24
|
+
updateView()
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@objc public var type: String = "blur" {
|
|
29
|
+
didSet {
|
|
30
|
+
updateView()
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@objc public var blurTypeString: String = "xlight" {
|
|
35
|
+
didSet {
|
|
36
|
+
updateView()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@objc public var glassType: String = "clear" {
|
|
41
|
+
didSet {
|
|
42
|
+
updateView()
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@objc public var reducedTransparencyFallbackColor: UIColor = .white {
|
|
47
|
+
didSet {
|
|
48
|
+
updateView()
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@objc public var isInteractive: Bool = true {
|
|
53
|
+
didSet {
|
|
54
|
+
updateView()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public override init(frame: CGRect) {
|
|
59
|
+
super.init(frame: frame)
|
|
60
|
+
setupHostingController()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
required init?(coder: NSCoder) {
|
|
64
|
+
super.init(coder: coder)
|
|
65
|
+
setupHostingController()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public override func layoutSubviews() {
|
|
69
|
+
super.layoutSubviews()
|
|
70
|
+
if hostingController == nil {
|
|
71
|
+
setupHostingController()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private func setupHostingController() {
|
|
76
|
+
// Completely remove old hosting controller
|
|
77
|
+
if let oldHosting = hostingController {
|
|
78
|
+
oldHosting.view.removeFromSuperview()
|
|
79
|
+
oldHosting.removeFromParent()
|
|
80
|
+
}
|
|
81
|
+
hostingController = nil
|
|
82
|
+
|
|
83
|
+
let blurStyle = blurStyleFromString(blurTypeString)
|
|
84
|
+
let swiftUIView = BasicColoredView(
|
|
85
|
+
glassTintColor: glassTintColor,
|
|
86
|
+
glassOpacity: glassOpacity,
|
|
87
|
+
blurAmount: blurAmount,
|
|
88
|
+
blurStyle: blurStyle,
|
|
89
|
+
type: type,
|
|
90
|
+
glassType: glassType,
|
|
91
|
+
reducedTransparencyFallbackColor: reducedTransparencyFallbackColor,
|
|
92
|
+
isInteractive: isInteractive
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
let hosting = UIHostingController(rootView: swiftUIView)
|
|
96
|
+
hosting.view.backgroundColor = .clear
|
|
97
|
+
hosting.view.translatesAutoresizingMaskIntoConstraints = false
|
|
98
|
+
|
|
99
|
+
addSubview(hosting.view)
|
|
100
|
+
NSLayoutConstraint.activate([
|
|
101
|
+
hosting.view.topAnchor.constraint(equalTo: topAnchor),
|
|
102
|
+
hosting.view.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
103
|
+
hosting.view.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
104
|
+
hosting.view.bottomAnchor.constraint(equalTo: bottomAnchor)
|
|
105
|
+
])
|
|
106
|
+
|
|
107
|
+
self.hostingController = hosting
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private func updateView() {
|
|
111
|
+
setupHostingController()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public override func didMoveToSuperview() {
|
|
115
|
+
super.didMoveToSuperview()
|
|
116
|
+
if superview != nil {
|
|
117
|
+
setupHostingController()
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public override func didMoveToWindow() {
|
|
122
|
+
super.didMoveToWindow()
|
|
123
|
+
if window != nil {
|
|
124
|
+
setupHostingController()
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
deinit {
|
|
129
|
+
if let hosting = hostingController {
|
|
130
|
+
hosting.view.removeFromSuperview()
|
|
131
|
+
hosting.removeFromParent()
|
|
132
|
+
}
|
|
133
|
+
hostingController = nil
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// BasicColoredView.swift
|
|
2
|
+
|
|
3
|
+
import SwiftUI
|
|
4
|
+
import UIKit
|
|
5
|
+
|
|
6
|
+
// MARK: - SwiftUI View Component
|
|
7
|
+
|
|
8
|
+
struct BasicColoredView: View {
|
|
9
|
+
var glassTintColor: UIColor
|
|
10
|
+
var glassOpacity: Double
|
|
11
|
+
var blurAmount: Double
|
|
12
|
+
var blurStyle: UIBlurEffect.Style
|
|
13
|
+
var type: String
|
|
14
|
+
var glassType: String
|
|
15
|
+
var reducedTransparencyFallbackColor: UIColor
|
|
16
|
+
var isInteractive: Bool
|
|
17
|
+
|
|
18
|
+
var body: some View {
|
|
19
|
+
let blurIntensity = mapBlurAmountToIntensity(blurAmount)
|
|
20
|
+
|
|
21
|
+
// Check if reduced transparency is enabled
|
|
22
|
+
let isReducedTransparencyEnabled = UIAccessibility.isReduceTransparencyEnabled
|
|
23
|
+
|
|
24
|
+
if isReducedTransparencyEnabled {
|
|
25
|
+
// Use fallback color when reduced transparency is enabled
|
|
26
|
+
Rectangle()
|
|
27
|
+
.fill(Color(reducedTransparencyFallbackColor))
|
|
28
|
+
} else {
|
|
29
|
+
if (type == "liquidGlass"){
|
|
30
|
+
if #available(iOS 26.0, *) {
|
|
31
|
+
let baseGlassEffect = glassEffectFromString(glassType)
|
|
32
|
+
Rectangle()
|
|
33
|
+
.glassEffect(
|
|
34
|
+
baseGlassEffect
|
|
35
|
+
.tint(Color(glassTintColor)
|
|
36
|
+
.opacity(glassOpacity))
|
|
37
|
+
.interactive(isInteractive)
|
|
38
|
+
, in: .rect)
|
|
39
|
+
|
|
40
|
+
} else {
|
|
41
|
+
// Use proper blur intensity control for liquid glass fallback
|
|
42
|
+
Rectangle()
|
|
43
|
+
.fill(Color(.clear))
|
|
44
|
+
.background(Blur(style: blurStyle, intensity: blurIntensity))
|
|
45
|
+
.overlay(
|
|
46
|
+
Color(glassTintColor)
|
|
47
|
+
.opacity(glassOpacity)
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
}else {
|
|
51
|
+
// Use proper blur intensity control for regular blur
|
|
52
|
+
Rectangle()
|
|
53
|
+
.fill(Color(.clear))
|
|
54
|
+
.background(Blur(style: blurStyle, intensity: blurIntensity))
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// BlurEffectView.swift
|
|
2
|
+
|
|
3
|
+
import SwiftUI
|
|
4
|
+
import UIKit
|
|
5
|
+
|
|
6
|
+
// MARK: - Blur View with proper intensity control
|
|
7
|
+
|
|
8
|
+
class BlurEffectView: UIVisualEffectView {
|
|
9
|
+
private var animator: UIViewPropertyAnimator?
|
|
10
|
+
private var blurStyle: UIBlurEffect.Style = .systemMaterial
|
|
11
|
+
private var intensity: Double = 1.0
|
|
12
|
+
|
|
13
|
+
override init(effect: UIVisualEffect?) {
|
|
14
|
+
super.init(effect: effect)
|
|
15
|
+
setupBlur()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
required init?(coder: NSCoder) {
|
|
19
|
+
super.init(coder: coder)
|
|
20
|
+
setupBlur()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
func updateBlur(style: UIBlurEffect.Style, intensity: Double) {
|
|
24
|
+
self.blurStyle = style
|
|
25
|
+
self.intensity = intensity
|
|
26
|
+
setupBlur()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private func setupBlur() {
|
|
30
|
+
// Clean up existing animator
|
|
31
|
+
if let animator = animator {
|
|
32
|
+
animator.stopAnimation(true)
|
|
33
|
+
animator.finishAnimation(at: .current)
|
|
34
|
+
}
|
|
35
|
+
animator = nil
|
|
36
|
+
|
|
37
|
+
// Reset effect
|
|
38
|
+
effect = nil
|
|
39
|
+
|
|
40
|
+
// Create new animator
|
|
41
|
+
animator = UIViewPropertyAnimator(duration: 1, curve: .linear)
|
|
42
|
+
animator?.addAnimations { [weak self] in
|
|
43
|
+
self?.effect = UIBlurEffect(style: self?.blurStyle ?? .systemMaterial)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Set intensity and pause
|
|
47
|
+
animator?.fractionComplete = intensity
|
|
48
|
+
animator?.pauseAnimation()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
deinit {
|
|
52
|
+
animator?.stopAnimation(true)
|
|
53
|
+
animator?.finishAnimation(at: .current)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// MARK: - SwiftUI Blur Wrapper
|
|
58
|
+
|
|
59
|
+
struct Blur: UIViewRepresentable {
|
|
60
|
+
var style: UIBlurEffect.Style = .systemMaterial
|
|
61
|
+
var intensity: Double = 1.0
|
|
62
|
+
|
|
63
|
+
func makeUIView(context: Context) -> BlurEffectView {
|
|
64
|
+
let effectView = BlurEffectView(effect: nil)
|
|
65
|
+
effectView.updateBlur(style: style, intensity: intensity)
|
|
66
|
+
return effectView
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
func updateUIView(_ uiView: BlurEffectView, context: Context) {
|
|
70
|
+
uiView.updateBlur(style: style, intensity: intensity)
|
|
71
|
+
}
|
|
72
|
+
}
|
package/package.json
CHANGED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
|
3
|
-
*
|
|
4
|
-
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
|
5
|
-
* once the code is regenerated.
|
|
6
|
-
*
|
|
7
|
-
* @generated by codegen project: GeneratePropsJavaDelegate.js
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
package com.facebook.react.viewmanagers;
|
|
11
|
-
|
|
12
|
-
import android.view.View;
|
|
13
|
-
import androidx.annotation.Nullable;
|
|
14
|
-
import com.facebook.react.uimanager.BaseViewManager;
|
|
15
|
-
import com.facebook.react.uimanager.BaseViewManagerDelegate;
|
|
16
|
-
import com.facebook.react.uimanager.LayoutShadowNode;
|
|
17
|
-
|
|
18
|
-
public class ReactNativeGlassViewManagerDelegate<T extends View, U extends BaseViewManager<T, ? extends LayoutShadowNode> & ReactNativeGlassViewManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
|
|
19
|
-
public ReactNativeGlassViewManagerDelegate(U viewManager) {
|
|
20
|
-
super(viewManager);
|
|
21
|
-
}
|
|
22
|
-
@Override
|
|
23
|
-
public void setProperty(T view, String propName, @Nullable Object value) {
|
|
24
|
-
switch (propName) {
|
|
25
|
-
case "glassType":
|
|
26
|
-
mViewManager.setGlassType(view, (String) value);
|
|
27
|
-
break;
|
|
28
|
-
case "glassAmount":
|
|
29
|
-
mViewManager.setGlassAmount(view, value == null ? 50f : ((Double) value).doubleValue());
|
|
30
|
-
break;
|
|
31
|
-
case "reducedTransparencyFallbackColor":
|
|
32
|
-
mViewManager.setReducedTransparencyFallbackColor(view, value == null ? null : (String) value);
|
|
33
|
-
break;
|
|
34
|
-
default:
|
|
35
|
-
super.setProperty(view, propName, value);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
|
3
|
-
*
|
|
4
|
-
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
|
5
|
-
* once the code is regenerated.
|
|
6
|
-
*
|
|
7
|
-
* @generated by codegen project: GeneratePropsJavaInterface.js
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
package com.facebook.react.viewmanagers;
|
|
11
|
-
|
|
12
|
-
import android.view.View;
|
|
13
|
-
import androidx.annotation.Nullable;
|
|
14
|
-
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;
|
|
15
|
-
|
|
16
|
-
public interface ReactNativeGlassViewManagerInterface<T extends View> extends ViewManagerWithGeneratedInterface {
|
|
17
|
-
void setGlassType(T view, @Nullable String value);
|
|
18
|
-
void setGlassAmount(T view, double value);
|
|
19
|
-
void setReducedTransparencyFallbackColor(T view, @Nullable String value);
|
|
20
|
-
}
|