Skip to content

Commit 62c0b5a

Browse files
committed
fix: improve subview foreach, use view as identifier
1 parent f564fde commit 62c0b5a

File tree

8 files changed

+34
-20
lines changed

8 files changed

+34
-20
lines changed

.changeset/major-sites-end.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'react-native-bottom-tabs': patch
3+
---
4+
5+
feat: improve subview foreach on iOS

packages/react-native-bottom-tabs/ios/TabBarFontSize.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import UIKit
21
import React
2+
import UIKit
33

44
enum TabBarFontSize {
55
/// Returns the default font size for tab bar item labels based on the current platform
@@ -51,7 +51,7 @@ enum TabBarFontSize {
5151
}
5252

5353
// Add color if provided
54-
if let color = color {
54+
if let color {
5555
attributes[.foregroundColor] = color
5656
}
5757

packages/react-native-bottom-tabs/ios/TabItemEventModifier.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ private final class TabBarDelegate: NSObject, UITabBarControllerDelegate {
2222
// Due to this, whether the tab prevents default has to be defined statically.
2323
if let index = tabBarController.viewControllers?.firstIndex(of: viewController) {
2424
let defaultPrevented = onClick?(index) ?? false
25-
25+
2626
return !defaultPrevented
2727
}
28-
28+
2929
return false
3030
}
3131
}
@@ -60,7 +60,7 @@ struct TabItemEventModifier: ViewModifier {
6060
}
6161

6262
// Create gesture handler
63-
let handler = LongPressGestureHandler(tabBar: tabController.tabBar, handler: { key, isLongPress in _ = onTabEvent(key,isLongPress) })
63+
let handler = LongPressGestureHandler(tabBar: tabController.tabBar) { key, isLongPress in _ = onTabEvent(key, isLongPress) }
6464
let gesture = UILongPressGestureRecognizer(target: handler, action: #selector(LongPressGestureHandler.handleLongPress(_:)))
6565
gesture.minimumPressDuration = 0.5
6666

packages/react-native-bottom-tabs/ios/TabView/LegacyTabView.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ struct LegacyTabView: AnyTabView {
1010
@ViewBuilder
1111
var body: some View {
1212
TabView(selection: $props.selectedPage) {
13-
ForEach(props.children.indices, id: \.self) { index in
14-
renderTabItem(at: index)
13+
ForEach(props.children) { child in
14+
if let index = props.children.firstIndex(of: child) {
15+
renderTabItem(at: index)
16+
}
1517
}
1618
.measureView { size in
1719
onLayout(size)
@@ -27,7 +29,7 @@ struct LegacyTabView: AnyTabView {
2729

2830
if !tabData.hidden || isFocused {
2931
let icon = props.icons[index]
30-
let child = props.children[safe: index] ?? PlatformView()
32+
let child = props.children[safe: index]?.view ?? PlatformView()
3133
let context = TabAppearContext(
3234
index: index,
3335
tabData: tabData,

packages/react-native-bottom-tabs/ios/TabView/NewTabView.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@ struct NewTabView: AnyTabView {
1111
@ViewBuilder
1212
var body: some View {
1313
TabView(selection: $props.selectedPage) {
14-
ForEach(props.children.indices, id: \.self) { index in
15-
if let tabData = props.items[safe: index] {
14+
ForEach(props.children) { child in
15+
if let index = props.children.firstIndex(of: child),
16+
let tabData = props.items[safe: index] {
1617
let isFocused = props.selectedPage == tabData.key
1718

1819
if !tabData.hidden || isFocused {
1920
let icon = props.icons[index]
2021

21-
let platformChild = props.children[safe: index] ?? PlatformView()
22-
let child = RepresentableView(view: platformChild)
2322
let context = TabAppearContext(
2423
index: index,
2524
tabData: tabData,
@@ -29,7 +28,7 @@ struct NewTabView: AnyTabView {
2928
)
3029

3130
Tab(value: tabData.key, role: tabData.role?.convert()) {
32-
child
31+
RepresentableView(view: child.view)
3332
.ignoresSafeArea(.container, edges: .all)
3433
.tabAppear(using: context)
3534
} label: {

packages/react-native-bottom-tabs/ios/TabViewImpl.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ struct TabViewImpl: View {
120120
}
121121
#endif
122122

123-
124123
#if !os(macOS)
125124
private func configureTransparentAppearance(tabBar: UITabBar, props: TabViewProps) {
126125
tabBar.barTintColor = props.barTintColor

packages/react-native-bottom-tabs/ios/TabViewProps.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ internal enum MinimizeBehavior: String {
2525

2626
public enum TabBarRole: String {
2727
case search
28-
28+
2929
@available(iOS 18, macOS 15, visionOS 2, tvOS 18, *)
3030
func convert() -> TabRole {
3131
switch self {
@@ -35,11 +35,20 @@ public enum TabBarRole: String {
3535
}
3636
}
3737

38+
struct IdentifiablePlatformView: Identifiable, Equatable {
39+
let id = UUID()
40+
let view: PlatformView
41+
42+
init(_ view: PlatformView) {
43+
self.view = view
44+
}
45+
}
46+
3847
/**
3948
Props that component accepts. SwiftUI view gets re-rendered when ObservableObject changes.
4049
*/
4150
class TabViewProps: ObservableObject {
42-
@Published var children: [PlatformView] = []
51+
@Published var children: [IdentifiablePlatformView] = []
4352
@Published var items: [TabInfo] = []
4453
@Published var selectedPage: String?
4554
@Published var icons: [Int: PlatformImage] = [:]

packages/react-native-bottom-tabs/ios/TabViewProvider.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ public final class TabInfo: NSObject {
177177
}
178178

179179
override public func didUpdateReactSubviews() {
180-
props.children = reactSubviews()
180+
props.children = reactSubviews().map(IdentifiablePlatformView.init)
181181
}
182182

183183
#if os(macOS)
@@ -218,15 +218,15 @@ public final class TabInfo: NSObject {
218218
#endif
219219
}
220220
}
221-
221+
222222
@objc(insertChild:atIndex:)
223223
public func insertChild(_ child: UIView, at index: Int) {
224224
guard index >= 0 && index <= props.children.count else {
225225
return
226226
}
227-
props.children.insert(child, at: index)
227+
props.children.insert(IdentifiablePlatformView(child), at: index)
228228
}
229-
229+
230230
@objc(removeChildAtIndex:)
231231
public func removeChild(at index: Int) {
232232
guard index >= 0 && index < props.children.count else {

0 commit comments

Comments
 (0)