diff --git a/.changeset/young-coats-start.md b/.changeset/young-coats-start.md new file mode 100644 index 00000000..5a58be4a --- /dev/null +++ b/.changeset/young-coats-start.md @@ -0,0 +1,5 @@ +--- +'react-native-bottom-tabs': patch +--- + +fix: improve subview management on iOS diff --git a/packages/react-native-bottom-tabs/ios/Fabric/RCTTabViewComponentView.mm b/packages/react-native-bottom-tabs/ios/Fabric/RCTTabViewComponentView.mm index 1cfc0167..9eee1811 100644 --- a/packages/react-native-bottom-tabs/ios/Fabric/RCTTabViewComponentView.mm +++ b/packages/react-native-bottom-tabs/ios/Fabric/RCTTabViewComponentView.mm @@ -57,7 +57,6 @@ @interface RCTTabViewComponentView () *_reactSubviews; } + (ComponentDescriptorProvider)componentDescriptorProvider @@ -69,7 +68,6 @@ - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); - _reactSubviews = [NSMutableArray new]; _tabViewProvider = [[TabViewProvider alloc] initWithDelegate:self]; self.contentView = _tabViewProvider; _props = defaultProps; @@ -84,24 +82,12 @@ + (BOOL)shouldBeRecycled return NO; } -- (void)layoutSubviews { - [super layoutSubviews]; - _tabViewProvider.children = [self reactSubviews]; -} - -- (NSArray *)reactSubviews -{ - return _reactSubviews; -} - - (void)mountChildComponentView:(PlatformView *)childComponentView index:(NSInteger)index { - [_reactSubviews insertObject:childComponentView atIndex:index]; - _tabViewProvider.children = [self reactSubviews]; + [_tabViewProvider insertChild:childComponentView atIndex:index]; } - (void)unmountChildComponentView:(PlatformView *)childComponentView index:(NSInteger)index { - [_reactSubviews removeObjectAtIndex:index]; - + [_tabViewProvider removeChildAtIndex:index]; [childComponentView removeFromSuperview]; } diff --git a/packages/react-native-bottom-tabs/ios/RepresentableView.swift b/packages/react-native-bottom-tabs/ios/RepresentableView.swift index 384227ee..09adaca4 100644 --- a/packages/react-native-bottom-tabs/ios/RepresentableView.swift +++ b/packages/react-native-bottom-tabs/ios/RepresentableView.swift @@ -2,6 +2,8 @@ import SwiftUI /** Helper used to render UIView inside of SwiftUI. + Wraps each view with an additional wrapper to avoid directly managing React Native views. + This solves issues where the layout would have weird artifacts.. */ struct RepresentableView: PlatformViewRepresentable { var view: PlatformView @@ -9,7 +11,9 @@ struct RepresentableView: PlatformViewRepresentable { #if os(macOS) func makeNSView(context: Context) -> PlatformView { - view + let wrapper = NSView() + wrapper.addSubview(view) + return wrapper } func updateNSView(_ nsView: PlatformView, context: Context) {} @@ -17,7 +21,9 @@ struct RepresentableView: PlatformViewRepresentable { #else func makeUIView(context: Context) -> PlatformView { - view + let wrapper = UIView() + wrapper.addSubview(view) + return wrapper } func updateUIView(_ uiView: PlatformView, context: Context) {} diff --git a/packages/react-native-bottom-tabs/ios/TabViewProvider.swift b/packages/react-native-bottom-tabs/ios/TabViewProvider.swift index 53e450c7..6920fe03 100644 --- a/packages/react-native-bottom-tabs/ios/TabViewProvider.swift +++ b/packages/react-native-bottom-tabs/ios/TabViewProvider.swift @@ -63,12 +63,6 @@ public final class TabInfo: NSObject { } } - @objc public var children: [PlatformView] = [] { - didSet { - props.children = children - } - } - @objc public var sidebarAdaptable: Bool = false { didSet { props.sidebarAdaptable = sidebarAdaptable @@ -221,6 +215,22 @@ public final class TabInfo: NSObject { #endif } } + + @objc(insertChild:atIndex:) + public func insertChild(_ child: UIView, at index: Int) { + guard index >= 0 && index <= props.children.count else { + return + } + props.children.insert(child, at: index) + } + + @objc(removeChildAtIndex:) + public func removeChild(at index: Int) { + guard index >= 0 && index < props.children.count else { + return + } + props.children.remove(at: index) + } private func loadIcons(_ icons: NSArray?) { // TODO: Diff the arrays and update only changed items.