Skip to content

Commit ff71011

Browse files
authored
fix: measure available space for views on iOS (#170)
* fix: measure available space for views on iOS * fix: refactor swift events * Create hungry-readers-remember.md * fix: sync, update example
1 parent ba8016c commit ff71011

14 files changed

+134
-72
lines changed

.changeset/hungry-readers-remember.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+
fix: measure available space for views on iOS, make sideBarAdaptable work properly

apps/example/ios/Podfile.lock

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,7 +1209,7 @@ PODS:
12091209
- ReactCommon/turbomodule/bridging
12101210
- ReactCommon/turbomodule/core
12111211
- Yoga
1212-
- react-native-bottom-tabs (0.6.0):
1212+
- react-native-bottom-tabs (0.7.1):
12131213
- DoubleConversion
12141214
- glog
12151215
- RCT-Folly (= 2024.01.01.00)
@@ -1222,7 +1222,7 @@ PODS:
12221222
- React-graphics
12231223
- React-ImageManager
12241224
- React-jsi
1225-
- react-native-bottom-tabs/common (= 0.6.0)
1225+
- react-native-bottom-tabs/common (= 0.7.1)
12261226
- React-NativeModulesApple
12271227
- React-RCTFabric
12281228
- React-rendererdebug
@@ -1234,7 +1234,7 @@ PODS:
12341234
- SDWebImageSVGCoder (>= 1.7.0)
12351235
- SwiftUIIntrospect (~> 1.0)
12361236
- Yoga
1237-
- react-native-bottom-tabs/common (0.6.0):
1237+
- react-native-bottom-tabs/common (0.7.1):
12381238
- DoubleConversion
12391239
- glog
12401240
- RCT-Folly (= 2024.01.01.00)
@@ -1945,7 +1945,7 @@ SPEC CHECKSUMS:
19451945
React-logger: d79b704bf215af194f5213a6b7deec50ba8e6a9b
19461946
React-Mapbuffer: b982d5bba94a8bc073bda48f0d27c9b28417fae3
19471947
React-microtasksnativemodule: 8fa285fed833a04a754bf575f8ded65fc240b88d
1948-
react-native-bottom-tabs: c17ddaf86c160134349c6325e020c1f38ee5f743
1948+
react-native-bottom-tabs: a08eaf6baf1b78375e17019536783dbbca3190ba
19491949
react-native-safe-area-context: 73505107f7c673cd550a561aeb6271f152c483b6
19501950
React-nativeconfig: 8c83d992b9cc7d75b5abe262069eaeea4349f794
19511951
React-NativeModulesApple: b8465afc883f5bf3fe8bac3767e394d581a5f123
@@ -1982,8 +1982,8 @@ SPEC CHECKSUMS:
19821982
SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c
19831983
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
19841984
SwiftUIIntrospect: fee9aa07293ee280373a591e1824e8ddc869ba5d
1985-
Yoga: aa3df615739504eebb91925fc9c58b4922ea9a08
1985+
Yoga: 055f92ad73f8c8600a93f0e25ac0b2344c3b07e6
19861986

19871987
PODFILE CHECKSUM: 1c1dbca3e400ef935aa9a150cb2dcb58fb8c4536
19881988

1989-
COCOAPODS: 1.14.3
1989+
COCOAPODS: 1.15.2

apps/example/src/Examples/NativeBottomTabsEmbeddedStacks.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ function ChatStackScreen() {
6767

6868
function NativeBottomTabsEmbeddedStacks() {
6969
return (
70-
<Tab.Navigator>
70+
<Tab.Navigator sidebarAdaptable>
7171
<Tab.Screen
7272
name="Article"
7373
component={ArticleStackScreen}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React
2+
3+
@objcMembers
4+
public class OnNativeLayoutEvent: NSObject, RCTEvent {
5+
private var size: CGSize
6+
public var viewTag: NSNumber
7+
8+
public var eventName: String {
9+
return "onNativeLayout"
10+
}
11+
12+
public init(reactTag: NSNumber, size: CGSize) {
13+
self.viewTag = reactTag
14+
self.size = size
15+
super.init()
16+
}
17+
18+
public class func moduleDotMethod() -> String {
19+
return "RCTEventEmitter.receiveEvent"
20+
}
21+
22+
public func arguments() -> [Any] {
23+
return [
24+
viewTag,
25+
RCTNormalizeInputEventName(eventName) ?? eventName,
26+
[
27+
"width": size.width,
28+
"height": size.height
29+
]
30+
]
31+
}
32+
}

packages/react-native-bottom-tabs/ios/Events/PageSelectedEvent.swift

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,25 @@
11
import React
22

3-
@objc public class PageSelectedEvent: NSObject, RCTEvent {
3+
@objcMembers
4+
public class PageSelectedEvent: NSObject, RCTEvent {
45
private var key: NSString
5-
@objc public var viewTag: NSNumber
6-
@objc public var coalescingKey: UInt16
6+
public var viewTag: NSNumber
77

8-
@objc public var eventName: String {
8+
public var eventName: String {
99
return "onPageSelected"
1010
}
1111

12-
@objc public init(reactTag: NSNumber, key: NSString, coalescingKey: UInt16) {
12+
public init(reactTag: NSNumber, key: NSString) {
1313
self.viewTag = reactTag
1414
self.key = key
15-
self.coalescingKey = coalescingKey
1615
super.init()
1716
}
1817

19-
@objc public func canCoalesce() -> Bool {
20-
return false
21-
}
22-
23-
@objc public class func moduleDotMethod() -> String {
18+
public class func moduleDotMethod() -> String {
2419
return "RCTEventEmitter.receiveEvent"
2520
}
2621

27-
@objc public func arguments() -> [Any] {
22+
public func arguments() -> [Any] {
2823
return [
2924
viewTag,
3025
RCTNormalizeInputEventName(eventName) ?? eventName,

packages/react-native-bottom-tabs/ios/Events/TabBarMeasuredEvent.swift

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,25 @@
11
import React
22

3-
@objc public class TabBarMeasuredEvent: NSObject, RCTEvent {
3+
@objcMembers
4+
public class TabBarMeasuredEvent: NSObject, RCTEvent {
45
private var height: NSInteger
5-
@objc public var viewTag: NSNumber
6-
@objc public var coalescingKey: UInt16
6+
public var viewTag: NSNumber
77

8-
@objc public var eventName: String {
8+
public var eventName: String {
99
return "onTabBarMeasured"
1010
}
1111

12-
@objc public init(reactTag: NSNumber, height: NSInteger, coalescingKey: UInt16) {
12+
public init(reactTag: NSNumber, height: NSInteger) {
1313
self.viewTag = reactTag
1414
self.height = height
15-
self.coalescingKey = coalescingKey
1615
super.init()
1716
}
1817

19-
@objc public func canCoalesce() -> Bool {
20-
return false
21-
}
22-
23-
@objc public class func moduleDotMethod() -> String {
18+
public class func moduleDotMethod() -> String {
2419
return "RCTEventEmitter.receiveEvent"
2520
}
2621

27-
@objc public func arguments() -> [Any] {
22+
public func arguments() -> [Any] {
2823
return [
2924
viewTag,
3025
RCTNormalizeInputEventName(eventName) ?? eventName,

packages/react-native-bottom-tabs/ios/Events/TabLongPressedEvent.swift

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,26 @@ import React
44
// RCTEvent is not defined for new arch.
55
protocol RCTEvent {}
66

7-
@objc public class TabLongPressEvent: NSObject, RCTEvent {
7+
@objcMembers
8+
public class TabLongPressEvent: NSObject, RCTEvent {
89
private var key: NSString
9-
@objc public var viewTag: NSNumber
10-
@objc public var coalescingKey: UInt16
10+
public var viewTag: NSNumber
1111

12-
@objc public var eventName: String {
12+
public var eventName: String {
1313
return "onTabLongPress"
1414
}
1515

16-
@objc public init(reactTag: NSNumber, key: NSString, coalescingKey: UInt16) {
16+
public init(reactTag: NSNumber, key: NSString) {
1717
self.viewTag = reactTag
1818
self.key = key
19-
self.coalescingKey = coalescingKey
2019
super.init()
2120
}
2221

23-
@objc public func canCoalesce() -> Bool {
24-
return false
25-
}
26-
27-
@objc public class func moduleDotMethod() -> String {
22+
public class func moduleDotMethod() -> String {
2823
return "RCTEventEmitter.receiveEvent"
2924
}
3025

31-
@objc public func arguments() -> [Any] {
26+
public func arguments() -> [Any] {
3227
return [
3328
viewTag,
3429
RCTNormalizeInputEventName(eventName) ?? eventName,

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,23 @@ extension View {
5050
customize: closure
5151
)
5252
}
53+
54+
55+
@MainActor
56+
@ViewBuilder
57+
func measureView(onLayout: @escaping (_ size: CGSize) -> Void) -> some View {
58+
self
59+
.background (
60+
GeometryReader { geometry in
61+
Color.clear
62+
.onChange(of: geometry.size) { newValue in
63+
onLayout(newValue)
64+
}
65+
.onAppear {
66+
onLayout(geometry.size)
67+
}
68+
}
69+
.ignoresSafeArea(.container, edges: .vertical)
70+
)
71+
}
5372
}

packages/react-native-bottom-tabs/ios/Fabric/RCTTabViewComponentView.mm

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,16 @@ - (void)onTabBarMeasuredWithHeight:(NSInteger)height reactTag:(NSNumber *)reactT
232232
}
233233
}
234234

235+
- (void)onLayoutWithSize:(CGSize)size reactTag:(NSNumber *)reactTag {
236+
auto eventEmitter = std::static_pointer_cast<const RNCTabViewEventEmitter>(_eventEmitter);
237+
if (eventEmitter) {
238+
eventEmitter->onNativeLayout(RNCTabViewEventEmitter::OnNativeLayout {
239+
.height = size.height,
240+
.width = size.width
241+
});
242+
}
243+
}
244+
235245
@end
236246

237247
Class<RCTComponentViewProtocol> RNCTabViewCls(void)

packages/react-native-bottom-tabs/ios/RCTTabViewViewManager.mm

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,10 @@
1212
@interface RCTTabView : RCTViewManager <TabViewProviderDelegate>
1313
@end
1414

15-
@implementation RCTTabView {
16-
uint16_t _coalescingKey;
17-
}
15+
@implementation RCTTabView
1816

1917
RCT_EXPORT_MODULE(RNCTabView)
2018

21-
- (instancetype)init
22-
{
23-
self = [super init];
24-
if (self) {
25-
_coalescingKey = 0;
26-
}
27-
return self;
28-
}
29-
3019
RCT_EXPORT_VIEW_PROPERTY(items, NSArray)
3120
RCT_EXPORT_VIEW_PROPERTY(onPageSelected, RCTDirectEventBlock)
3221
RCT_EXPORT_VIEW_PROPERTY(onTabLongPress, RCTDirectEventBlock)
@@ -51,17 +40,22 @@ - (instancetype)init
5140
// MARK: TabViewProviderDelegate
5241

5342
- (void)onLongPressWithKey:(NSString *)key reactTag:(NSNumber *)reactTag {
54-
auto event = [[TabLongPressEvent alloc] initWithReactTag:reactTag key:key coalescingKey:_coalescingKey++];
43+
auto event = [[TabLongPressEvent alloc] initWithReactTag:reactTag key:key];
5544
[self.bridge.eventDispatcher sendEvent:event];
5645
}
5746

5847
- (void)onPageSelectedWithKey:(NSString *)key reactTag:(NSNumber *)reactTag {
59-
auto event = [[PageSelectedEvent alloc] initWithReactTag:reactTag key:key coalescingKey:_coalescingKey++];
48+
auto event = [[PageSelectedEvent alloc] initWithReactTag:reactTag key:key];
6049
[self.bridge.eventDispatcher sendEvent:event];
6150
}
6251

6352
- (void)onTabBarMeasuredWithHeight:(NSInteger)height reactTag:(NSNumber *)reactTag {
64-
auto event = [[TabBarMeasuredEvent alloc] initWithReactTag:reactTag height:height coalescingKey:_coalescingKey++];
53+
auto event = [[TabBarMeasuredEvent alloc] initWithReactTag:reactTag height:height];
54+
[self.bridge.eventDispatcher sendEvent:event];
55+
}
56+
57+
- (void)onLayoutWithSize:(CGSize)size reactTag:(NSNumber *)reactTag {
58+
auto event = [[OnNativeLayoutEvent alloc] initWithReactTag:reactTag size:size];
6559
[self.bridge.eventDispatcher sendEvent:event];
6660
}
6761

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,17 @@ struct TabViewImpl: View {
5959

6060
var onSelect: (_ key: String) -> Void
6161
var onLongPress: (_ key: String) -> Void
62+
var onLayout: (_ size: CGSize) -> Void
6263
var onTabBarMeasured: (_ height: Int) -> Void
6364

6465
var body: some View {
6566
TabView(selection: $props.selectedPage) {
6667
ForEach(props.children.indices, id: \.self) { index in
6768
renderTabItem(at: index)
6869
}
70+
.measureView(onLayout: { size in
71+
onLayout(size)
72+
})
6973
}
7074
#if !os(tvOS)
7175
.onTabItemEvent({ index, isLongPress in
@@ -326,13 +330,10 @@ extension View {
326330
) -> some View {
327331
if flag {
328332
self
329-
.ignoresSafeArea(.container, edges: .all)
330-
.frame(idealWidth: frame.width, idealHeight: frame.height)
333+
.ignoresSafeArea(.container, edges: .vertical)
331334
} else {
332335
self
333-
.ignoresSafeArea(.container, edges: .horizontal)
334336
.ignoresSafeArea(.container, edges: .bottom)
335-
.frame(idealWidth: frame.width, idealHeight: frame.height)
336337
}
337338
}
338339

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

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ import React
44
import SDWebImage
55
import SDWebImageSVGCoder
66

7-
@objc public final class TabInfo: NSObject {
8-
@objc public let key: String
9-
@objc public let title: String
10-
@objc public let badge: String
11-
@objc public let sfSymbol: String
12-
@objc public let activeTintColor: UIColor?
13-
@objc public let hidden: Bool
14-
15-
@objc
7+
@objcMembers
8+
public final class TabInfo: NSObject {
9+
public let key: String
10+
public let title: String
11+
public let badge: String
12+
public let sfSymbol: String
13+
public let activeTintColor: UIColor?
14+
public let hidden: Bool
15+
1616
public init(
1717
key: String,
1818
title: String,
@@ -35,6 +35,7 @@ import SDWebImageSVGCoder
3535
func onPageSelected(key: String, reactTag: NSNumber?)
3636
func onLongPress(key: String, reactTag: NSNumber?)
3737
func onTabBarMeasured(height: Int, reactTag: NSNumber?)
38+
func onLayout(size: CGSize, reactTag: NSNumber?)
3839
}
3940

4041
@objc public class TabViewProvider: UIView {
@@ -184,6 +185,8 @@ import SDWebImageSVGCoder
184185
self.delegate?.onPageSelected(key: key, reactTag: self.reactTag)
185186
} onLongPress: { key in
186187
self.delegate?.onLongPress(key: key, reactTag: self.reactTag)
188+
} onLayout: { size in
189+
self.delegate?.onLayout(size: size, reactTag: self.reactTag)
187190
} onTabBarMeasured: { height in
188191
self.delegate?.onTabBarMeasured(height: height, reactTag: self.reactTag)
189192
})

0 commit comments

Comments
 (0)