From 6a1b54fc1ae51c210ed6c2a81207a83723e08e27 Mon Sep 17 00:00:00 2001 From: Krzysztof Ligarski Date: Wed, 8 Oct 2025 13:13:18 +0200 Subject: [PATCH 1/3] change tab bar item only when necessary --- .../RNSBottomTabsScreenComponentView.mm | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm b/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm index 0341fec26c..227faea9a8 100644 --- a/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm +++ b/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm @@ -172,7 +172,7 @@ - (void)updateContentScrollViewEdgeEffectsIfExists #pragma mark - Prop update utils -- (void)updateTabBarItem +- (void)changeBaseTabBarItem { UITabBarItem *tabBarItem = nil; if (_systemItem != RNSBottomTabsScreenSystemItemNone) { @@ -181,14 +181,24 @@ - (void)updateTabBarItem tabBarItem = [[UITabBarItem alloc] initWithTabBarSystemItem:systemItem tag:0]; } else { tabBarItem = [[UITabBarItem alloc] init]; - tabBarItem.title = _title; } - tabBarItem.badgeValue = _badgeValue; - _controller.tabBarItem = tabBarItem; } +- (void)updateTabBarItem +{ + UITabBarItem *tabBarItem = _controller.tabBarItem; + + if (![tabBarItem.title isEqualToString:_title]) { + tabBarItem.title = _title; + } + + if (![tabBarItem.badgeValue isEqualToString:_badgeValue]) { + tabBarItem.badgeValue = _badgeValue; + } +} + #pragma mark - RNSSafeAreaProviding - (UIEdgeInsets)providerSafeAreaInsets @@ -222,6 +232,7 @@ - (void)updateProps:(const facebook::react::Props::Shared &)props bool tabItemNeedsAppearanceUpdate{false}; bool tabScreenOrientationNeedsUpdate{false}; + bool tabBarItemNeedsBaseChange{false}; bool tabBarItemNeedsUpdate{false}; bool scrollEdgeEffectsNeedUpdate{false}; @@ -274,33 +285,38 @@ - (void)updateProps:(const facebook::react::Props::Shared &)props if (newComponentProps.iconType != oldComponentProps.iconType) { _iconType = rnscreens::conversion::RNSBottomTabsIconTypeFromIcon(newComponentProps.iconType); tabItemNeedsAppearanceUpdate = YES; - tabBarItemNeedsUpdate = YES; } if (newComponentProps.iconImageSource != oldComponentProps.iconImageSource) { _iconImageSource = rnscreens::conversion::RCTImageSourceFromImageSourceAndIconType(&newComponentProps.iconImageSource, _iconType); tabItemNeedsAppearanceUpdate = YES; - tabBarItemNeedsUpdate = YES; } if (newComponentProps.iconSfSymbolName != oldComponentProps.iconSfSymbolName) { _iconSfSymbolName = RCTNSStringFromStringNilIfEmpty(newComponentProps.iconSfSymbolName); tabItemNeedsAppearanceUpdate = YES; - tabBarItemNeedsUpdate = YES; + + // In order to restore the default system item icon, we recreate the tab bar item. + if (_iconType == RNSBottomTabsIconTypeSfSymbol && _iconSfSymbolName == nil) { + tabBarItemNeedsBaseChange = YES; + } } if (newComponentProps.selectedIconImageSource != oldComponentProps.selectedIconImageSource) { _selectedIconImageSource = rnscreens::conversion::RCTImageSourceFromImageSourceAndIconType( &newComponentProps.selectedIconImageSource, _iconType); tabItemNeedsAppearanceUpdate = YES; - tabBarItemNeedsUpdate = YES; } if (newComponentProps.selectedIconSfSymbolName != oldComponentProps.selectedIconSfSymbolName) { _selectedIconSfSymbolName = RCTNSStringFromStringNilIfEmpty(newComponentProps.selectedIconSfSymbolName); tabItemNeedsAppearanceUpdate = YES; - tabBarItemNeedsUpdate = YES; + + // In order to restore the default system item icon, we recreate the tab bar item. + if (_iconType == RNSBottomTabsIconTypeSfSymbol && _selectedIconSfSymbolName == nil) { + tabBarItemNeedsBaseChange = YES; + } } if (newComponentProps.specialEffects.repeatedTabSelection.popToRoot != @@ -334,7 +350,7 @@ - (void)updateProps:(const facebook::react::Props::Shared &)props if (newComponentProps.systemItem != oldComponentProps.systemItem) { _systemItem = rnscreens::conversion::RNSBottomTabsScreenSystemItemFromReactRNSBottomTabsScreenSystemItem( newComponentProps.systemItem); - tabBarItemNeedsUpdate = YES; + tabBarItemNeedsBaseChange = YES; } if (newComponentProps.bottomScrollEdgeEffect != oldComponentProps.bottomScrollEdgeEffect) { @@ -367,6 +383,11 @@ - (void)updateProps:(const facebook::react::Props::Shared &)props scrollEdgeEffectsNeedUpdate = YES; } + if (tabBarItemNeedsBaseChange) { + [self changeBaseTabBarItem]; + tabBarItemNeedsUpdate = YES; + } + if (tabBarItemNeedsUpdate) { [self updateTabBarItem]; From b477a04841ee23e1759fbb1a831d66f93cf1b025 Mon Sep 17 00:00:00 2001 From: Krzysztof Ligarski Date: Wed, 8 Oct 2025 13:23:28 +0200 Subject: [PATCH 2/3] change approach for restoring systemItem's default icon to limit the bug --- ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm | 10 ---------- ios/bottom-tabs/RNSTabBarAppearanceCoordinator.mm | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm b/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm index 227faea9a8..1823b9a00a 100644 --- a/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm +++ b/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm @@ -296,11 +296,6 @@ - (void)updateProps:(const facebook::react::Props::Shared &)props if (newComponentProps.iconSfSymbolName != oldComponentProps.iconSfSymbolName) { _iconSfSymbolName = RCTNSStringFromStringNilIfEmpty(newComponentProps.iconSfSymbolName); tabItemNeedsAppearanceUpdate = YES; - - // In order to restore the default system item icon, we recreate the tab bar item. - if (_iconType == RNSBottomTabsIconTypeSfSymbol && _iconSfSymbolName == nil) { - tabBarItemNeedsBaseChange = YES; - } } if (newComponentProps.selectedIconImageSource != oldComponentProps.selectedIconImageSource) { @@ -312,11 +307,6 @@ - (void)updateProps:(const facebook::react::Props::Shared &)props if (newComponentProps.selectedIconSfSymbolName != oldComponentProps.selectedIconSfSymbolName) { _selectedIconSfSymbolName = RCTNSStringFromStringNilIfEmpty(newComponentProps.selectedIconSfSymbolName); tabItemNeedsAppearanceUpdate = YES; - - // In order to restore the default system item icon, we recreate the tab bar item. - if (_iconType == RNSBottomTabsIconTypeSfSymbol && _selectedIconSfSymbolName == nil) { - tabBarItemNeedsBaseChange = YES; - } } if (newComponentProps.specialEffects.repeatedTabSelection.popToRoot != diff --git a/ios/bottom-tabs/RNSTabBarAppearanceCoordinator.mm b/ios/bottom-tabs/RNSTabBarAppearanceCoordinator.mm index dff5cbf534..a24a6f1bef 100644 --- a/ios/bottom-tabs/RNSTabBarAppearanceCoordinator.mm +++ b/ios/bottom-tabs/RNSTabBarAppearanceCoordinator.mm @@ -55,10 +55,20 @@ - (void)setIconsForTabBarItem:(UITabBarItem *)tabBarItem if (screenView.iconType == RNSBottomTabsIconTypeSfSymbol) { if (screenView.iconSfSymbolName != nil) { tabBarItem.image = [UIImage systemImageNamed:screenView.iconSfSymbolName]; + } else if (screenView.systemItem != RNSBottomTabsScreenSystemItemNone) { + // Restore default system item icon + UITabBarSystemItem systemItem = + rnscreens::conversion::RNSBottomTabsScreenSystemItemToUITabBarSystemItem(screenView.systemItem); + tabBarItem.image = [[UITabBarItem alloc] initWithTabBarSystemItem:systemItem tag:0].image; } if (screenView.selectedIconSfSymbolName != nil) { tabBarItem.selectedImage = [UIImage systemImageNamed:screenView.selectedIconSfSymbolName]; + } else if (screenView.systemItem != RNSBottomTabsScreenSystemItemNone) { + // Restore default system item icon + UITabBarSystemItem systemItem = + rnscreens::conversion::RNSBottomTabsScreenSystemItemToUITabBarSystemItem(screenView.systemItem); + tabBarItem.selectedImage = [[UITabBarItem alloc] initWithTabBarSystemItem:systemItem tag:0].selectedImage; } } else if (imageLoader != nil) { bool isTemplate = screenView.iconType == RNSBottomTabsIconTypeTemplate; From 75b28bac0099450dbbf61d58b3f8d67fbcc26752 Mon Sep 17 00:00:00 2001 From: Krzysztof Ligarski Date: Wed, 8 Oct 2025 13:31:22 +0200 Subject: [PATCH 3/3] update Paper implementation --- .../RNSBottomTabsScreenComponentView.mm | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm b/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm index 1823b9a00a..373add689b 100644 --- a/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm +++ b/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm @@ -35,6 +35,7 @@ @implementation RNSBottomTabsScreenComponentView { #if !RCT_NEW_ARCH_ENABLED BOOL _tabItemNeedsAppearanceUpdate; BOOL _tabScreenOrientationNeedsUpdate; + BOOL _tabBarItemNeedsBaseChange; BOOL _tabBarItemNeedsUpdate; BOOL _scrollEdgeEffectsNeedUpdate; #endif // !RCT_NEW_ARCH_ENABLED @@ -64,6 +65,7 @@ - (void)initState #if !RCT_NEW_ARCH_ENABLED _tabItemNeedsAppearanceUpdate = NO; _tabScreenOrientationNeedsUpdate = NO; + _tabBarItemNeedsBaseChange = NO; _tabBarItemNeedsUpdate = NO; _scrollEdgeEffectsNeedUpdate = NO; #endif @@ -456,6 +458,13 @@ - (void)didSetProps:(NSArray *)changedProps // didSetProps will always be called because tabKey prop is required. _isOverrideScrollViewContentInsetAdjustmentBehaviorSet = YES; + if (_tabBarItemNeedsBaseChange) { + [self changeBaseTabBarItem]; + _tabBarItemNeedsBaseChange = NO; + + _tabBarItemNeedsUpdate = YES; + } + if (_tabBarItemNeedsUpdate) { [self updateTabBarItem]; _tabBarItemNeedsUpdate = NO; @@ -512,35 +521,30 @@ - (void)setIconType:(RNSBottomTabsIconType)iconType { _iconType = iconType; _tabItemNeedsAppearanceUpdate = YES; - _tabBarItemNeedsUpdate = YES; } - (void)setIconImageSource:(RCTImageSource *)iconImageSource { _iconImageSource = iconImageSource; _tabItemNeedsAppearanceUpdate = YES; - _tabBarItemNeedsUpdate = YES; } - (void)setIconSfSymbolName:(NSString *)iconSfSymbolName { _iconSfSymbolName = [NSString rnscreens_stringOrNilIfEmpty:iconSfSymbolName]; _tabItemNeedsAppearanceUpdate = YES; - _tabBarItemNeedsUpdate = YES; } - (void)setSelectedIconImageSource:(RCTImageSource *)selectedIconImageSource { _selectedIconImageSource = selectedIconImageSource; _tabItemNeedsAppearanceUpdate = YES; - _tabBarItemNeedsUpdate = YES; } - (void)setSelectedIconSfSymbolName:(NSString *)selectedIconSfSymbolName { _selectedIconSfSymbolName = [NSString rnscreens_stringOrNilIfEmpty:selectedIconSfSymbolName]; _tabItemNeedsAppearanceUpdate = YES; - _tabBarItemNeedsUpdate = YES; } - (void)setBottomScrollEdgeEffect:(RNSScrollEdgeEffect)bottomScrollEdgeEffect @@ -607,7 +611,7 @@ - (void)setScrollEdgeAppearance:(NSDictionary *)scrollEdgeAppearanceProps - (void)setSystemItem:(RNSBottomTabsScreenSystemItem)systemItem { _systemItem = systemItem; - _tabBarItemNeedsUpdate = YES; + _tabBarItemNeedsBaseChange = YES; } - (void)setOrientation:(RNSOrientation)orientation