Skip to content

Commit 1bb9a09

Browse files
authored
fix(ios): simplify background setup and support blur + color (#423)
* feat(ios): simplify background setup and always keep blur view in hierarchy * docs: update changelog for #423 * chore: delete .claude
1 parent 24bacbd commit 1bb9a09

4 files changed

Lines changed: 51 additions & 70 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### 🐛 Bug fixes
66

7+
- **iOS**: Fixed `backgroundBlur` and `backgroundColor` not working together. ([#423](https://github.com/lodev09/react-native-true-sheet/pull/423) by [@lodev09](https://github.com/lodev09))
78
- **iOS**: Fixed `present()` called from `useEffect` not working due to mount event not firing. ([#421](https://github.com/lodev09/react-native-true-sheet/pull/421) by [@lodev09](https://github.com/lodev09))
89
- Fixed sheet content becoming empty after rapidly presenting/dismissing. ([#419](https://github.com/lodev09/react-native-true-sheet/pull/419) by [@lodev09](https://github.com/lodev09))
910
- Auto re-present sheet when returning from screen dismiss (modal or navigation pop). ([#412](https://github.com/lodev09/react-native-true-sheet/pull/412) by [@lodev09](https://github.com/lodev09))

example/shared/src/components/sheets/BasicSheet.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { forwardRef, useRef, useState, type Ref, useImperativeHandle } from 'rea
22
import { StyleSheet } from 'react-native';
33
import { TrueSheet, type TrueSheetProps } from '@lodev09/react-native-true-sheet';
44

5-
import { DARK, DARK_BLUE, FOOTER_HEIGHT, GAP, SPACING, times } from '../../utils';
5+
import { BLUE, DARK, DARK_BLUE, FOOTER_HEIGHT, GAP, SPACING, times } from '../../utils';
66
import { DemoContent } from '../DemoContent';
77
import { Footer } from '../Footer';
88
import { Button } from '../Button';
@@ -20,6 +20,7 @@ export const BasicSheet = forwardRef((props: BasicSheetProps, ref: Ref<TrueSheet
2020
const sheetRef = useRef<TrueSheet>(null);
2121
const childSheet = useRef<TrueSheet>(null);
2222
const [contentCount, setContentCount] = useState(0);
23+
const [detentIndex, setDetentIndex] = useState(0);
2324

2425
const resize = async (index: number) => {
2526
await sheetRef.current?.resize(index);
@@ -84,17 +85,20 @@ export const BasicSheet = forwardRef((props: BasicSheetProps, ref: Ref<TrueSheet
8485
`Basic sheet presented at index: ${e.nativeEvent.index}, position: ${e.nativeEvent.position}`
8586
)
8687
}
87-
onDetentChange={(e) =>
88+
onDetentChange={(e) => {
89+
setDetentIndex(e.nativeEvent.index);
8890
console.log(
8991
`Detent changed to index:`,
9092
e.nativeEvent.index,
9193
'position:',
9294
e.nativeEvent.position
93-
)
94-
}
95+
);
96+
}}
9597
onMount={() => {
9698
console.log('BasicSheet is ready!');
9799
}}
100+
backgroundBlur={detentIndex > 0 ? 'system-material' : undefined}
101+
backgroundColor={detentIndex > 0 ? BLUE : undefined}
98102
header={<Header />}
99103
footer={<Footer />}
100104
{...rest}

ios/TrueSheetViewController.mm

Lines changed: 16 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ - (void)viewDidLoad {
167167
[super viewDidLoad];
168168
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
169169

170+
_blurView = [[TrueSheetBlurView alloc] init];
171+
[_blurView addToView:self.view];
172+
170173
_grabberView = [[TrueSheetGrabberView alloc] init];
171174
_grabberView.hidden = YES;
172175
[_grabberView addToView:self.view];
@@ -688,61 +691,30 @@ - (void)resizeToDetentIndex:(NSInteger)index {
688691
}
689692

690693
- (void)setupBackground {
691-
#if RNTS_IPHONE_OS_VERSION_AVAILABLE(26_1)
692-
BOOL useBackgroundEffect = NO;
693-
if (@available(iOS 26.1, *)) {
694-
useBackgroundEffect = !self.isDesignCompatibilityMode;
695-
}
696-
697-
// iOS 26.1+: use native backgroundEffect when only backgroundBlur is set (no backgroundColor)
698-
// Fall back to TrueSheetBlurView when blur intensity is set (not 100%) since
699-
// sheet.backgroundEffect doesn't support intensity control
700-
if (@available(iOS 26.1, *)) {
701-
if (useBackgroundEffect) {
702-
BOOL hasCustomIntensity = self.blurIntensity && [self.blurIntensity floatValue] < 100;
703-
if (!self.backgroundColor && self.backgroundBlur && self.backgroundBlur.length > 0) {
704-
if (hasCustomIntensity) {
705-
// Clear native effect to allow custom blur view with intensity
706-
self.sheet.backgroundEffect = [UIColorEffect effectWithColor:[UIColor clearColor]];
707-
} else {
708-
UIBlurEffectStyle style = [BlurUtil blurEffectStyleFromString:self.backgroundBlur];
709-
self.sheet.backgroundEffect = [UIBlurEffect effectWithStyle:style];
710-
return;
711-
}
712-
}
713-
}
714-
}
715-
#endif
716-
717694
NSString *effectiveBackgroundBlur = self.backgroundBlur;
718695
if (@available(iOS 26.0, *)) {
719696
// iOS 26+ has default liquid glass effect
720697
} else if ((!effectiveBackgroundBlur || effectiveBackgroundBlur.length == 0) && !self.backgroundColor) {
721698
effectiveBackgroundBlur = @"system-material";
722699
}
723700

724-
BOOL blurChanged = ![_blurView.backgroundBlur isEqualToString:effectiveBackgroundBlur];
725-
726-
if (_blurView && blurChanged) {
727-
[_blurView removeFromSuperview];
728-
_blurView = nil;
729-
}
701+
BOOL hasBlur = effectiveBackgroundBlur && effectiveBackgroundBlur.length > 0;
730702

731-
if (effectiveBackgroundBlur && effectiveBackgroundBlur.length > 0) {
732-
if (!_blurView) {
733-
_blurView = [[TrueSheetBlurView alloc] init];
734-
[_blurView addToView:self.view];
735-
}
736-
_blurView.backgroundBlur = effectiveBackgroundBlur;
737-
_blurView.blurIntensity = self.blurIntensity;
738-
_blurView.blurInteraction = self.blurInteraction;
739-
[_blurView applyBlurEffect];
740-
}
703+
_blurView.backgroundBlur = hasBlur ? effectiveBackgroundBlur : nil;
704+
_blurView.blurIntensity = self.blurIntensity;
705+
_blurView.blurInteraction = self.blurInteraction;
706+
[_blurView applyBlurEffect];
741707

742708
#if RNTS_IPHONE_OS_VERSION_AVAILABLE(26_1)
743709
if (@available(iOS 26.1, *)) {
744-
if (useBackgroundEffect && self.backgroundColor) {
745-
self.sheet.backgroundEffect = [UIColorEffect effectWithColor:self.backgroundColor];
710+
if (!self.isDesignCompatibilityMode) {
711+
if (self.backgroundColor) {
712+
self.sheet.backgroundEffect = [UIColorEffect effectWithColor:self.backgroundColor];
713+
} else if (hasBlur) {
714+
self.sheet.backgroundEffect = [UIColorEffect effectWithColor:[UIColor clearColor]];
715+
} else {
716+
self.sheet.backgroundEffect = nil;
717+
}
746718
return;
747719
}
748720
}

ios/core/TrueSheetBlurView.mm

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,41 +34,45 @@ - (void)addToView:(UIView *)parentView {
3434
[parentView insertSubview:self atIndex:0];
3535
}
3636

37+
- (void)clearAnimator {
38+
if (_blurAnimator) {
39+
[_blurAnimator stopAnimation:YES];
40+
_blurAnimator = nil;
41+
}
42+
}
43+
3744
- (void)applyBlurEffect {
3845
self.userInteractionEnabled = self.blurInteraction;
3946

40-
// Create animator only once
41-
if (!_blurAnimator) {
42-
UIBlurEffectStyle style = [BlurUtil blurEffectStyleFromString:self.backgroundBlur];
43-
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:style];
47+
if (!self.backgroundBlur || self.backgroundBlur.length == 0) {
48+
[self clearAnimator];
49+
self.effect = nil;
50+
return;
51+
}
52+
53+
UIBlurEffectStyle style = [BlurUtil blurEffectStyleFromString:self.backgroundBlur];
54+
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:style];
55+
56+
CGFloat intensity =
57+
(self.blurIntensity && [self.blurIntensity floatValue] >= 0) ? [self.blurIntensity floatValue] / 100.0 : 1.0;
4458

59+
if (intensity >= 1.0) {
60+
[self clearAnimator];
61+
self.effect = blurEffect;
62+
return;
63+
}
64+
65+
if (!_blurAnimator) {
4566
__weak __typeof(self) weakSelf = self;
4667
_blurAnimator = [[UIViewPropertyAnimator alloc] initWithDuration:1.0
4768
curve:UIViewAnimationCurveLinear
4869
animations:^{
4970
weakSelf.effect = blurEffect;
5071
}];
51-
_blurAnimator.pausesOnCompletion = YES;
5272
}
5373

54-
// Update intensity
55-
CGFloat intensity =
56-
(self.blurIntensity && [self.blurIntensity floatValue] >= 0) ? [self.blurIntensity floatValue] / 100.0 : 1.0;
74+
_blurAnimator.pausesOnCompletion = YES;
5775
_blurAnimator.fractionComplete = intensity;
5876
}
5977

60-
- (void)willMoveToSuperview:(UIView *)newSuperview {
61-
[super willMoveToSuperview:newSuperview];
62-
63-
// Clean up when removed from superview
64-
if (!newSuperview) {
65-
if (_blurAnimator) {
66-
[_blurAnimator stopAnimation:YES];
67-
_blurAnimator = nil;
68-
}
69-
70-
self.effect = nil;
71-
}
72-
}
73-
7478
@end

0 commit comments

Comments
 (0)