Skip to content

Commit 2bf8aee

Browse files
authored
Merge pull request #99 from sbaiahmed1/fix/perf-issues-with-blur-navigation
fix(android,ios): prevent blur initialization delay and z-ordering bug
2 parents ad7864a + a1f21c2 commit 2bf8aee

5 files changed

Lines changed: 46 additions & 20 deletions

File tree

android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurView.kt

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,12 @@ class ReactNativeBlurView : BlurViewGroup {
107107

108108
if (isBlurInitialized) return
109109

110-
// Defer the blur root swap to next frame so the view tree is fully mounted
111-
val runnable = Runnable {
112-
initRunnable = null
113-
if (isBlurInitialized) return@Runnable
114-
swapBlurRootToScreenAncestor()
115-
initializeBlur()
116-
}
117-
initRunnable = runnable
118-
post(runnable)
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+
swapBlurRootToScreenAncestor()
115+
initializeBlur()
119116
}
120117

121118
/**

example/app.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"scheme": "exampleapp",
99
"userInterfaceStyle": "automatic",
1010
"ios": {
11-
"icon": "./assets/expo.icon"
11+
"icon": "./assets/expo.icon",
12+
"bundleIdentifier": "com.sbaiahmed1.reactnativeblurexampleapp"
1213
},
1314
"android": {
1415
"adaptiveIcon": {

example/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"scripts": {
77
"start": "expo start",
88
"android": "expo run:android",
9+
"prebuild:ios": "expo prebuild --platform ios --clean",
910
"ios": "expo run:ios",
1011
"web": "expo start --web",
1112
"lint": "expo lint",
@@ -47,4 +48,4 @@
4748
"react-native-monorepo-config": "*",
4849
"typescript": "~5.9.2"
4950
}
50-
}
51+
}

ios/Views/AdvancedBlurView.swift

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,14 @@ import UIKit
6868
hosting.view.backgroundColor = .clear
6969
hosting.view.translatesAutoresizingMaskIntoConstraints = false
7070

71-
addSubview(hosting.view)
71+
// Insert at index 0 to ensure it stays behind any potential subviews (though usually this view has no children)
72+
// This fixes the z-ordering bug where blur covers content
73+
if !subviews.isEmpty {
74+
insertSubview(hosting.view, at: 0)
75+
} else {
76+
addSubview(hosting.view)
77+
}
78+
7279
NSLayoutConstraint.activate([
7380
hosting.view.topAnchor.constraint(equalTo: topAnchor),
7481
hosting.view.leadingAnchor.constraint(equalTo: leadingAnchor),
@@ -80,8 +87,20 @@ import UIKit
8087
}
8188

8289
private func updateView() {
83-
if hostingController != nil {
84-
setupHostingController()
90+
if let hosting = hostingController {
91+
// Update the existing controller's root view to avoid expensive recreation
92+
// This fixes performance bottlenecks and state synchronization issues
93+
let blurStyle = blurStyleFromString(blurTypeString)
94+
let swiftUIView = BasicColoredView(
95+
blurAmount: blurAmount,
96+
blurStyle: blurStyle,
97+
ignoreSafeArea: ignoreSafeArea,
98+
reducedTransparencyFallbackColor: reducedTransparencyFallbackColor
99+
)
100+
hosting.rootView = swiftUIView
101+
hosting.view.setNeedsLayout()
102+
} else {
103+
setupHostingController()
85104
}
86105
}
87106

ios/Views/VibrancyEffectView.swift

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,24 @@ import UIKit
6868
let blurEffect = UIBlurEffect(style: style)
6969
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
7070

71-
// Use animator to control blur intensity
72-
blurAnimator = UIViewPropertyAnimator(duration: 1, curve: .linear)
73-
blurAnimator?.addAnimations { [weak self] in
74-
self?.blurEffectView.effect = blurEffect
75-
self?.vibrancyEffectView.effect = vibrancyEffect
71+
// Set effects directly first to ensure they are visible
72+
// Animating them from nil often causes issues with UIVibrancyEffect
73+
blurEffectView.effect = blurEffect
74+
vibrancyEffectView.effect = vibrancyEffect
75+
76+
// Create animator to adjust intensity
77+
blurAnimator = UIViewPropertyAnimator(duration: 1, curve: .linear) { [weak self] in
78+
self?.blurEffectView.effect = nil
79+
self?.vibrancyEffectView.effect = nil
7680
}
7781

7882
// Convert blurAmount (0-100) to intensity (0.0-1.0)
83+
// We reverse the logic:
84+
// fractionComplete = 0.0 -> effects are fully applied (start state)
85+
// fractionComplete = 1.0 -> effects are removed (end state)
86+
// So to get desired intensity X, we set fractionComplete to (1 - X)
7987
let intensity = min(max(blurAmount / 100.0, 0.0), 1.0)
80-
blurAnimator?.fractionComplete = intensity
88+
blurAnimator?.fractionComplete = 1.0 - intensity
8189

8290
// Stop the animation at the current state
8391
DispatchQueue.main.async { [weak self, weak blurAnimator] in

0 commit comments

Comments
 (0)