Skip to content
Merged
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/young-coats-start.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'react-native-bottom-tabs': patch
---

fix: improve subview management on iOS
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ @interface RCTTabViewComponentView () <RCTRNCTabViewViewProtocol, TabViewProvide

@implementation RCTTabViewComponentView {
TabViewProvider *_tabViewProvider;
NSMutableArray<PlatformView *> *_reactSubviews;
}

+ (ComponentDescriptorProvider)componentDescriptorProvider
Expand All @@ -69,7 +68,6 @@ - (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<const RNCTabViewProps>();
_reactSubviews = [NSMutableArray new];
_tabViewProvider = [[TabViewProvider alloc] initWithDelegate:self];
self.contentView = _tabViewProvider;
_props = defaultProps;
Expand All @@ -84,24 +82,12 @@ + (BOOL)shouldBeRecycled
return NO;
}

- (void)layoutSubviews {
[super layoutSubviews];
_tabViewProvider.children = [self reactSubviews];
}

- (NSArray<PlatformView *> *)reactSubviews
{
return _reactSubviews;
}

- (void)mountChildComponentView:(PlatformView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
[_reactSubviews insertObject:childComponentView atIndex:index];
_tabViewProvider.children = [self reactSubviews];
[_tabViewProvider insertChild:childComponentView atIndex:index];
}

- (void)unmountChildComponentView:(PlatformView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
[_reactSubviews removeObjectAtIndex:index];

[_tabViewProvider removeChildAtIndex:index];
[childComponentView removeFromSuperview];
}

Expand Down
10 changes: 8 additions & 2 deletions packages/react-native-bottom-tabs/ios/RepresentableView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,28 @@ 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

#if os(macOS)

func makeNSView(context: Context) -> PlatformView {
view
let wrapper = NSView()
wrapper.addSubview(view)
return wrapper
}

func updateNSView(_ nsView: PlatformView, context: Context) {}

#else

func makeUIView(context: Context) -> PlatformView {
view
let wrapper = UIView()
wrapper.addSubview(view)
return wrapper
}

func updateUIView(_ uiView: PlatformView, context: Context) {}
Expand Down
22 changes: 16 additions & 6 deletions packages/react-native-bottom-tabs/ios/TabViewProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@
}

@objc public protocol TabViewProviderDelegate {
func onPageSelected(key: String, reactTag: NSNumber?)

Check warning on line 41 in packages/react-native-bottom-tabs/ios/TabViewProvider.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)
func onLongPress(key: String, reactTag: NSNumber?)

Check warning on line 42 in packages/react-native-bottom-tabs/ios/TabViewProvider.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)
func onTabBarMeasured(height: Int, reactTag: NSNumber?)

Check warning on line 43 in packages/react-native-bottom-tabs/ios/TabViewProvider.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)
func onLayout(size: CGSize, reactTag: NSNumber?)

Check warning on line 44 in packages/react-native-bottom-tabs/ios/TabViewProvider.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)
}

@objc public class TabViewProvider: PlatformView {
Expand All @@ -57,18 +57,12 @@
@objc var onTabBarMeasured: RCTDirectEventBlock?
@objc var onNativeLayout: RCTDirectEventBlock?

@objc public var icons: NSArray? {

Check warning on line 60 in packages/react-native-bottom-tabs/ios/TabViewProvider.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)
didSet {
loadIcons(icons)
}
}

@objc public var children: [PlatformView] = [] {
didSet {
props.children = children
}
}

@objc public var sidebarAdaptable: Bool = false {
didSet {
props.sidebarAdaptable = sidebarAdaptable
Expand All @@ -87,7 +81,7 @@
}
}

@objc public var selectedPage: NSString? {

Check warning on line 84 in packages/react-native-bottom-tabs/ios/TabViewProvider.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)
didSet {
props.selectedPage = selectedPage as? String
}
Expand All @@ -99,13 +93,13 @@
}
}

@objc public var scrollEdgeAppearance: NSString? {

Check warning on line 96 in packages/react-native-bottom-tabs/ios/TabViewProvider.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)
didSet {
props.scrollEdgeAppearance = scrollEdgeAppearance as? String
}
}

@objc public var minimizeBehavior: NSString? {

Check warning on line 102 in packages/react-native-bottom-tabs/ios/TabViewProvider.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)
didSet {
props.minimizeBehavior = MinimizeBehavior(rawValue: minimizeBehavior as? String ?? "")
}
Expand All @@ -117,7 +111,7 @@
}
}

@objc var items: NSArray? {

Check warning on line 114 in packages/react-native-bottom-tabs/ios/TabViewProvider.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)
didSet {
props.items = parseTabData(from: items)
}
Expand All @@ -141,7 +135,7 @@
}
}

@objc public var fontFamily: NSString? {

Check warning on line 138 in packages/react-native-bottom-tabs/ios/TabViewProvider.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)
didSet {
props.fontFamily = fontFamily as? String
}
Expand Down Expand Up @@ -221,6 +215,22 @@
#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.
Expand Down
Loading