Skip to content

Commit ca3ead3

Browse files
authored
iOS 26 bottom tab fix (#8245)
* partially working * cleanup * test update
1 parent ec7ffbe commit ca3ead3

66 files changed

Lines changed: 11318 additions & 46 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ios/BottomTabsAppearancePresenter.mm

Lines changed: 69 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ @implementation BottomTabsAppearancePresenter
77
#pragma mark - public
88

99
- (void)applyBackgroundColor:(UIColor *)backgroundColor translucent:(BOOL)translucent {
10+
if (@available(iOS 26.0, *)) {
11+
[self setTabBarTransparentBackground];
12+
self.tabBar.backgroundColor = UIColor.clearColor;
13+
return;
14+
}
1015
if (translucent)
1116
[self setTabBarTranslucent:YES];
1217
else if (backgroundColor.isTransparent)
@@ -19,26 +24,33 @@ - (void)applyBackgroundColor:(UIColor *)backgroundColor translucent:(BOOL)transl
1924

2025
- (void)applyTabBarBorder:(RNNBottomTabsOptions *)options {
2126
if (options.borderColor.hasValue || options.borderWidth.hasValue) {
22-
for (UIViewController *childViewController in self.tabBarController.childViewControllers)
23-
childViewController.tabBarItem.standardAppearance.shadowImage = [UIImage
24-
imageWithSize:CGSizeMake(1.0, [[options.borderWidth withDefault:@(0.1)] floatValue])
25-
color:[options.borderColor withDefault:UIColor.blackColor]];
27+
UIImage *borderImage = [UIImage
28+
imageWithSize:CGSizeMake(1.0, [[options.borderWidth withDefault:@(0.1)] floatValue])
29+
color:[options.borderColor withDefault:UIColor.blackColor]];
30+
31+
for (UIViewController *childViewController in self.tabBarController.childViewControllers) {
32+
childViewController.tabBarItem.standardAppearance.shadowImage = borderImage;
33+
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
34+
if (@available(iOS 15.0, *)) {
35+
childViewController.tabBarItem.scrollEdgeAppearance.shadowImage = borderImage;
36+
}
37+
#endif
38+
}
2639
}
2740
}
2841

2942
- (void)setTabBarBackgroundColor:(UIColor *)backgroundColor {
30-
[self setTabBarOpaqueBackground];
31-
for (UIViewController *childViewController in self.tabBarController.childViewControllers) {
32-
childViewController.tabBarItem.standardAppearance.backgroundColor = backgroundColor;
33-
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
34-
if (@available(iOS 15.0, *)) {
35-
childViewController.tabBarItem.scrollEdgeAppearance.backgroundColor = backgroundColor;
36-
}
37-
#endif
43+
UITabBarAppearance *appearance = [self appearanceWithColor:backgroundColor];
44+
[self applyTabBarAppearance:appearance];
45+
self.tabBar.barTintColor = backgroundColor;
46+
self.tabBar.translucent = NO;
47+
if (@available(iOS 26.0, *)) {
48+
self.tabBar.backgroundColor = backgroundColor;
3849
}
3950
}
4051

4152
- (void)setTabBarTranslucent:(BOOL)translucent {
53+
self.tabBar.translucent = translucent;
4254
if (translucent)
4355
[self setTabBarTranslucentBackground];
4456
else
@@ -48,38 +60,63 @@ - (void)setTabBarTranslucent:(BOOL)translucent {
4860
#pragma mark - private
4961

5062
- (void)setTabBarDefaultBackground {
51-
[self setTabBarOpaqueBackground];
63+
if (@available(iOS 26.0, *)) {
64+
[self setTabBarTransparentBackground];
65+
self.tabBar.backgroundColor = UIColor.clearColor;
66+
} else {
67+
[self setTabBarOpaqueBackground];
68+
}
5269
}
5370

5471
- (void)setTabBarTranslucentBackground {
55-
for (UIViewController *childViewController in self.tabBarController.childViewControllers) {
56-
[childViewController.tabBarItem.standardAppearance configureWithDefaultBackground];
57-
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
58-
if (@available(iOS 15.0, *)) {
59-
[childViewController.tabBarItem.scrollEdgeAppearance configureWithDefaultBackground];
60-
}
61-
#endif
62-
}
72+
UITabBarAppearance *appearance = [UITabBarAppearance new];
73+
[appearance configureWithDefaultBackground];
74+
[self applyTabBarAppearance:appearance];
75+
self.tabBar.barTintColor = nil;
6376
}
6477

6578
- (void)setTabBarTransparentBackground {
66-
for (UIViewController *childViewController in self.tabBarController.childViewControllers) {
67-
[childViewController.tabBarItem.standardAppearance configureWithTransparentBackground];
68-
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
69-
if (@available(iOS 15.0, *)) {
70-
[childViewController.tabBarItem
71-
.scrollEdgeAppearance configureWithTransparentBackground];
72-
}
73-
#endif
74-
}
79+
UITabBarAppearance *appearance = [UITabBarAppearance new];
80+
[appearance configureWithTransparentBackground];
81+
appearance.backgroundEffect = nil;
82+
appearance.backgroundColor = UIColor.clearColor;
83+
[self applyTabBarAppearance:appearance];
84+
self.tabBar.barTintColor = UIColor.clearColor;
7585
}
7686

7787
- (void)setTabBarOpaqueBackground {
88+
UITabBarAppearance *appearance = [self appearanceWithColor:nil];
89+
[self applyTabBarAppearance:appearance];
90+
self.tabBar.barTintColor = UIColor.systemBackgroundColor;
91+
self.tabBar.translucent = NO;
92+
}
93+
94+
#pragma mark - helpers
95+
96+
- (UITabBarAppearance *)appearanceWithColor:(UIColor *)color {
97+
UITabBarAppearance *appearance = [UITabBarAppearance new];
98+
[appearance configureWithOpaqueBackground];
99+
appearance.backgroundEffect = nil;
100+
appearance.shadowColor = nil;
101+
UIColor *resolvedColor = color ?: UIColor.systemBackgroundColor;
102+
appearance.backgroundColor = resolvedColor;
103+
appearance.backgroundImage = [UIImage imageWithSize:CGSizeMake(1, 1) color:resolvedColor];
104+
return appearance;
105+
}
106+
107+
- (void)applyTabBarAppearance:(UITabBarAppearance *)appearance {
108+
self.tabBar.standardAppearance = appearance;
109+
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
110+
if (@available(iOS 15.0, *)) {
111+
self.tabBar.scrollEdgeAppearance = [appearance copy];
112+
}
113+
#endif
114+
78115
for (UIViewController *childViewController in self.tabBarController.childViewControllers) {
79-
[childViewController.tabBarItem.standardAppearance configureWithOpaqueBackground];
116+
childViewController.tabBarItem.standardAppearance = [appearance copy];
80117
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
81118
if (@available(iOS 15.0, *)) {
82-
[childViewController.tabBarItem.scrollEdgeAppearance configureWithOpaqueBackground];
119+
childViewController.tabBarItem.scrollEdgeAppearance = [appearance copy];
83120
}
84121
#endif
85122
}

ios/BottomTabsBasePresenter.mm

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ - (void)applyOptions:(RNNNavigationOptions *)options {
2727
[bottomTabs setTabBarVisible:[withDefault.bottomTabs.visible withDefault:YES]];
2828

2929
[bottomTabs.view setBackgroundColor:[withDefault.layout.backgroundColor withDefault:nil]];
30+
[bottomTabs setTabBarHideShadow:[withDefault.bottomTabs.hideShadow withDefault:NO]];
31+
if (options.bottomTabs.barStyle.hasValue) {
32+
[bottomTabs setTabBarStyle:[RNNConvert UIBarStyle:options.bottomTabs.barStyle.get]];
33+
}
3034
[self applyBackgroundColor:[withDefault.bottomTabs.backgroundColor withDefault:nil]
3135
translucent:[withDefault.bottomTabs.translucent withDefault:NO]];
32-
[bottomTabs setTabBarHideShadow:[withDefault.bottomTabs.hideShadow withDefault:NO]];
33-
[bottomTabs setTabBarStyle:[RNNConvert UIBarStyle:[withDefault.bottomTabs.barStyle
34-
withDefault:@"default"]]];
3536
[self applyTabBarBorder:withDefault.bottomTabs];
3637
[self applyTabBarShadow:withDefault.bottomTabs.shadow];
3738
}
@@ -65,7 +66,7 @@ - (void)mergeOptions:(RNNNavigationOptions *)mergeOptions
6566
}
6667

6768
if (mergeOptions.bottomTabs.translucent.hasValue) {
68-
[bottomTabs setTabBarTranslucent:mergeOptions.bottomTabs.translucent.get];
69+
[self setTabBarTranslucent:mergeOptions.bottomTabs.translucent.get];
6970
}
7071

7172
if (mergeOptions.bottomTabs.hideShadow.hasValue) {

ios/RNNBottomTabsController.mm

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,27 @@ - (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo
4848
eventEmitter:eventEmitter
4949
childViewControllers:childViewControllers];
5050

51-
if (@available(iOS 13.0, *)) {
52-
self.tabBar.standardAppearance = [UITabBarAppearance new];
53-
}
51+
if (@available(iOS 26.0, *)) {
52+
UITabBarAppearance *appearance = [UITabBarAppearance new];
53+
[appearance configureWithTransparentBackground];
54+
appearance.backgroundEffect = nil;
55+
appearance.backgroundColor = UIColor.clearColor;
56+
self.tabBar.standardAppearance = appearance;
57+
self.tabBar.scrollEdgeAppearance = [appearance copy];
58+
self.tabBar.barTintColor = UIColor.clearColor;
59+
} else if (@available(iOS 13.0, *)) {
60+
UITabBarAppearance *appearance = [UITabBarAppearance new];
61+
[appearance configureWithOpaqueBackground];
62+
appearance.backgroundEffect = nil;
63+
appearance.backgroundColor = UIColor.systemBackgroundColor;
64+
self.tabBar.standardAppearance = appearance;
5465
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
55-
if (@available(iOS 15.0, *)) {
56-
self.tabBar.scrollEdgeAppearance = [UITabBarAppearance new];
57-
}
66+
if (@available(iOS 15.0, *)) {
67+
self.tabBar.scrollEdgeAppearance = [appearance copy];
68+
}
5869
#endif
70+
self.tabBar.translucent = NO;
71+
}
5972

6073
[self createTabBarItems:childViewControllers];
6174

ios/RNNBottomTabsOptions.mm

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,11 @@ - (void)mergeOptions:(RNNBottomTabsOptions *)options {
7272
}
7373

7474
- (BOOL)shouldDrawBehind {
75-
return [self.drawBehind withDefault:NO] || [self.translucent withDefault:NO] ||
75+
BOOL defaultDrawBehind = NO;
76+
if (@available(iOS 26.0, *)) {
77+
defaultDrawBehind = YES;
78+
}
79+
return [self.drawBehind withDefault:defaultDrawBehind] || [self.translucent withDefault:NO] ||
7680
![self.visible withDefault:YES];
7781
}
7882

ios/RNNComponentViewController.mm

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ - (void)renderReactViewIfNeeded {
9191
}];
9292
self.reactView.backgroundColor = UIColor.clearColor;
9393
self.reactView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
94+
self.reactView.clipsToBounds = YES;
9495
[self.reactView setFrame:self.view.frame];
9596
[self.view addSubview:self.reactView];
9697
[self updateReactViewFrame];
@@ -118,14 +119,15 @@ - (void)updateReactViewFrame {
118119
if (self.isViewLoaded && self.reactView) {
119120
CGFloat bottomInset = self.shouldDrawBehindBottomTabs ? 0 : self.view.safeAreaInsets.bottom;
120121
CGFloat topInset = self.shouldDrawBehindTopBar ? 0 : self.view.safeAreaInsets.top;
122+
121123
[self.reactView setFrame:CGRectMake(0, topInset, self.view.frame.size.width,
122124
self.view.frame.size.height - topInset - bottomInset)];
123125
}
124126
}
125127

126128
- (BOOL)shouldDrawBehindBottomTabs {
127-
return (!self.tabBarController.tabBar || self.tabBarController.tabBar.isHidden ||
128-
_drawBehindBottomTabs);
129+
return !self.tabBarController.tabBar || self.tabBarController.tabBar.isHidden ||
130+
_drawBehindBottomTabs;
129131
}
130132

131133
- (BOOL)shouldDrawBehindTopBar {

playground/ios/NavigationTests/RNNBottomTabsAppearancePresenterTest.mm

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ - (void)testApplyOptions_shouldSetDefaultEmptyOptions {
5757
[[(id)self.uut expect] applyBackgroundColor:nil translucent:NO];
5858
[[self.boundViewController expect] setTabBarHideShadow:NO];
5959
[[self.boundViewController expect] setTabBarVisible:YES];
60-
[[self.boundViewController expect] setTabBarStyle:UIBarStyleDefault];
6160
[self.uut applyOptions:emptyOptions];
6261
[self.boundViewController verify];
6362
}

0 commit comments

Comments
 (0)