Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/quiet-more-control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'react-native-bottom-tabs': patch
---

Preserve the system More tab's label and icon when tabs overflow, including in iPhone Duo landscape.
38 changes: 23 additions & 15 deletions packages/react-native-bottom-tabs/ios/TabViewImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
@Weak var tabBar: NSTabView?
#else
@Weak var tabBar: UITabBar?
@Weak var moreTabBarItem: UITabBarItem?
#endif

@ViewBuilder
Expand Down Expand Up @@ -70,8 +71,11 @@
tabBar = tabController
#else
tabBar = tabController.tabBar
#if os(iOS)
moreTabBarItem = tabController.moreNavigationController.tabBarItem
#endif
updateTabBarAppearance(props: props, tabBar: tabController.tabBar)
updateTabBarItemImages(props: props, tabBar: tabController.tabBar)
updateTabBarItemImages(props: props, tabBar: tabController.tabBar, moreTabBarItem: moreTabBarItem)
if !props.tabBarHidden {
onTabBarMeasured(
Int(tabController.tabBar.frame.size.height)
Expand All @@ -80,7 +84,7 @@
#endif
}
#if !os(macOS)
.configureAppearance(props: props, tabBar: tabBar)
.configureAppearance(props: props, tabBar: tabBar, moreTabBarItem: moreTabBarItem)
#endif
.tintColor(props.selectedActiveTintColor)
.getSidebarAdaptable(enabled: props.sidebarAdaptable ?? false)
Expand Down Expand Up @@ -115,16 +119,16 @@
}

#if !os(macOS)
private func updateTabBarItemImages(props: TabViewProps, tabBar: UITabBar?) {
private func updateTabBarItemImages(props: TabViewProps, tabBar: UITabBar?, moreTabBarItem: UITabBarItem?) {
guard let tabBar,
let items = tabBar.items
else { return }

configureTabBarItemImages(items: items, props: props)
configureTabBarItemImages(items: items, props: props, moreTabBarItem: moreTabBarItem)

DispatchQueue.main.async { [weak tabBar] in
guard let tabBar, let items = tabBar.items else { return }
configureTabBarItemImages(items: items, props: props)
configureTabBarItemImages(items: items, props: props, moreTabBarItem: moreTabBarItem)
}
}

Expand Down Expand Up @@ -219,8 +223,12 @@
}
}

private func configureTabBarItemImages(items: [UITabBarItem], props: TabViewProps) {
private func configureTabBarItemImages(items: [UITabBarItem], props: TabViewProps, moreTabBarItem: UITabBarItem?) {

Check warning on line 226 in packages/react-native-bottom-tabs/ios/TabViewImpl.swift

View workflow job for this annotation

GitHub Actions / swift-lint

Function Body Length Violation: Function body should span 50 lines or less excluding comments and whitespace: currently spans 62 lines (function_body_length)
for (tabBarIndex, item) in items.enumerated() {
// UIKit inserts its own overflow item when the available space is limited.
// Its label and icon must not be replaced with the next route's appearance.
guard item !== moreTabBarItem else { continue }

guard let tabData = props.filteredItems[safe: tabBarIndex],
let itemIndex = props.items.firstIndex(where: { $0.key == tabData.key })
else { continue }
Expand Down Expand Up @@ -359,9 +367,9 @@
let attributes: [NSAttributedString.Key: Any] = [
.font: font,
.foregroundColor: color,
.paragraphStyle: paragraphStyle,

Check warning on line 370 in packages/react-native-bottom-tabs/ios/TabViewImpl.swift

View workflow job for this annotation

GitHub Actions / swift-lint

Trailing Comma Violation: Collection literals should not have trailing commas (trailing_comma)
]
let titleSize = (title as NSString).size(withAttributes: attributes)

Check warning on line 372 in packages/react-native-bottom-tabs/ios/TabViewImpl.swift

View workflow job for this annotation

GitHub Actions / swift-lint

Legacy Objective-C Reference Type Violation: Prefer Swift value types to bridged Objective-C reference types (legacy_objc_type)
let imageSize = CGSize(
width: max(iconSize.width, ceil(titleSize.width)) + 8,
height: iconSize.height + 3 + ceil(titleSize.height)
Expand All @@ -388,7 +396,7 @@

tintedIcon.draw(in: iconFrame)

(title as NSString).draw(

Check warning on line 399 in packages/react-native-bottom-tabs/ios/TabViewImpl.swift

View workflow job for this annotation

GitHub Actions / swift-lint

Legacy Objective-C Reference Type Violation: Prefer Swift value types to bridged Objective-C reference types (legacy_objc_type)
in: CGRect(
x: 0,
y: iconSize.height + 3,
Expand Down Expand Up @@ -456,7 +464,7 @@

#if !os(macOS)
@ViewBuilder
func configureAppearance(props: TabViewProps, tabBar: UITabBar?) -> some View {
func configureAppearance(props: TabViewProps, tabBar: UITabBar?, moreTabBarItem: UITabBarItem?) -> some View {
self
.onChange(of: props.barTintColor) { _ in
updateTabBarAppearance(props: props, tabBar: tabBar)
Expand All @@ -469,36 +477,36 @@
}
.onChange(of: props.inactiveTintColor) { _ in
updateTabBarAppearance(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar, moreTabBarItem: moreTabBarItem)
}
.onChange(of: props.activeTintColor) { _ in
updateTabBarAppearance(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar, moreTabBarItem: moreTabBarItem)
}
.onChange(of: props.selectedActiveTintColor) { newValue in
tabBar?.tintColor = newValue
}
.onChange(of: props.iconsRevision) { _ in
updateTabBarItemImages(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar, moreTabBarItem: moreTabBarItem)
}
.onChange(of: props.labeled) { _ in
updateTabBarItemImages(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar, moreTabBarItem: moreTabBarItem)
}
.onChange(of: props.fontSize) { _ in
updateTabBarAppearance(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar, moreTabBarItem: moreTabBarItem)
}
.onChange(of: props.fontFamily) { _ in
updateTabBarAppearance(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar, moreTabBarItem: moreTabBarItem)
}
.onChange(of: props.fontWeight) { _ in
updateTabBarAppearance(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar, moreTabBarItem: moreTabBarItem)
}
.onChange(of: props.experimentalBakedTintColors) { _ in
updateTabBarAppearance(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar)
updateTabBarItemImages(props: props, tabBar: tabBar, moreTabBarItem: moreTabBarItem)
}
.onChange(of: props.tabBarHidden) { newValue in
tabBar?.isHidden = newValue
Expand Down Expand Up @@ -563,4 +571,4 @@
self
}
}
}

Check warning on line 574 in packages/react-native-bottom-tabs/ios/TabViewImpl.swift

View workflow job for this annotation

GitHub Actions / swift-lint

File Length Violation: File should contain 400 lines or less: currently contains 574 (file_length)
Loading