Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: measure available space for views on iOS #170

Merged
merged 4 commits into from
Dec 3, 2024
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/hungry-readers-remember.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-native-bottom-tabs": patch
---

fix: measure available space for views on iOS, make sideBarAdaptable work properly
12 changes: 6 additions & 6 deletions apps/example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1209,7 +1209,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-bottom-tabs (0.6.0):
- react-native-bottom-tabs (0.7.1):
- DoubleConversion
- glog
- RCT-Folly (= 2024.01.01.00)
Expand All @@ -1222,7 +1222,7 @@ PODS:
- React-graphics
- React-ImageManager
- React-jsi
- react-native-bottom-tabs/common (= 0.6.0)
- react-native-bottom-tabs/common (= 0.7.1)
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
Expand All @@ -1234,7 +1234,7 @@ PODS:
- SDWebImageSVGCoder (>= 1.7.0)
- SwiftUIIntrospect (~> 1.0)
- Yoga
- react-native-bottom-tabs/common (0.6.0):
- react-native-bottom-tabs/common (0.7.1):
- DoubleConversion
- glog
- RCT-Folly (= 2024.01.01.00)
Expand Down Expand Up @@ -1945,7 +1945,7 @@ SPEC CHECKSUMS:
React-logger: d79b704bf215af194f5213a6b7deec50ba8e6a9b
React-Mapbuffer: b982d5bba94a8bc073bda48f0d27c9b28417fae3
React-microtasksnativemodule: 8fa285fed833a04a754bf575f8ded65fc240b88d
react-native-bottom-tabs: c17ddaf86c160134349c6325e020c1f38ee5f743
react-native-bottom-tabs: a08eaf6baf1b78375e17019536783dbbca3190ba
react-native-safe-area-context: 73505107f7c673cd550a561aeb6271f152c483b6
React-nativeconfig: 8c83d992b9cc7d75b5abe262069eaeea4349f794
React-NativeModulesApple: b8465afc883f5bf3fe8bac3767e394d581a5f123
Expand Down Expand Up @@ -1982,8 +1982,8 @@ SPEC CHECKSUMS:
SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
SwiftUIIntrospect: fee9aa07293ee280373a591e1824e8ddc869ba5d
Yoga: aa3df615739504eebb91925fc9c58b4922ea9a08
Yoga: 055f92ad73f8c8600a93f0e25ac0b2344c3b07e6

PODFILE CHECKSUM: 1c1dbca3e400ef935aa9a150cb2dcb58fb8c4536

COCOAPODS: 1.14.3
COCOAPODS: 1.15.2
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function ChatStackScreen() {

function NativeBottomTabsEmbeddedStacks() {
return (
<Tab.Navigator>
<Tab.Navigator sidebarAdaptable>
<Tab.Screen
name="Article"
component={ArticleStackScreen}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React

@objcMembers
public class OnNativeLayoutEvent: NSObject, RCTEvent {
private var size: CGSize
public var viewTag: NSNumber

public var eventName: String {
return "onNativeLayout"
}

public init(reactTag: NSNumber, size: CGSize) {
self.viewTag = reactTag
self.size = size
super.init()
}

public class func moduleDotMethod() -> String {
return "RCTEventEmitter.receiveEvent"
}

public func arguments() -> [Any] {
return [
viewTag,
RCTNormalizeInputEventName(eventName) ?? eventName,
[
"width": size.width,
"height": size.height
]
]
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
import React

@objc public class PageSelectedEvent: NSObject, RCTEvent {
@objcMembers
public class PageSelectedEvent: NSObject, RCTEvent {
private var key: NSString
@objc public var viewTag: NSNumber
@objc public var coalescingKey: UInt16
public var viewTag: NSNumber

@objc public var eventName: String {
public var eventName: String {
return "onPageSelected"
}

@objc public init(reactTag: NSNumber, key: NSString, coalescingKey: UInt16) {
public init(reactTag: NSNumber, key: NSString) {
self.viewTag = reactTag
self.key = key
self.coalescingKey = coalescingKey
super.init()
}

@objc public func canCoalesce() -> Bool {
return false
}

@objc public class func moduleDotMethod() -> String {
public class func moduleDotMethod() -> String {
return "RCTEventEmitter.receiveEvent"
}

@objc public func arguments() -> [Any] {
public func arguments() -> [Any] {
return [
viewTag,
RCTNormalizeInputEventName(eventName) ?? eventName,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
import React

@objc public class TabBarMeasuredEvent: NSObject, RCTEvent {
@objcMembers
public class TabBarMeasuredEvent: NSObject, RCTEvent {
private var height: NSInteger
@objc public var viewTag: NSNumber
@objc public var coalescingKey: UInt16
public var viewTag: NSNumber

@objc public var eventName: String {
public var eventName: String {
return "onTabBarMeasured"
}

@objc public init(reactTag: NSNumber, height: NSInteger, coalescingKey: UInt16) {
public init(reactTag: NSNumber, height: NSInteger) {
self.viewTag = reactTag
self.height = height
self.coalescingKey = coalescingKey
super.init()
}

@objc public func canCoalesce() -> Bool {
return false
}

@objc public class func moduleDotMethod() -> String {
public class func moduleDotMethod() -> String {
return "RCTEventEmitter.receiveEvent"
}

@objc public func arguments() -> [Any] {
public func arguments() -> [Any] {
return [
viewTag,
RCTNormalizeInputEventName(eventName) ?? eventName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,26 @@ import React
// RCTEvent is not defined for new arch.
protocol RCTEvent {}

@objc public class TabLongPressEvent: NSObject, RCTEvent {
@objcMembers
public class TabLongPressEvent: NSObject, RCTEvent {
private var key: NSString
@objc public var viewTag: NSNumber
@objc public var coalescingKey: UInt16
public var viewTag: NSNumber

@objc public var eventName: String {
public var eventName: String {
return "onTabLongPress"
}

@objc public init(reactTag: NSNumber, key: NSString, coalescingKey: UInt16) {
public init(reactTag: NSNumber, key: NSString) {
self.viewTag = reactTag
self.key = key
self.coalescingKey = coalescingKey
super.init()
}

@objc public func canCoalesce() -> Bool {
return false
}

@objc public class func moduleDotMethod() -> String {
public class func moduleDotMethod() -> String {
return "RCTEventEmitter.receiveEvent"
}

@objc public func arguments() -> [Any] {
public func arguments() -> [Any] {
return [
viewTag,
RCTNormalizeInputEventName(eventName) ?? eventName,
Expand Down
19 changes: 19 additions & 0 deletions packages/react-native-bottom-tabs/ios/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,23 @@ extension View {
customize: closure
)
}


@MainActor
@ViewBuilder
func measureView(onLayout: @escaping (_ size: CGSize) -> Void) -> some View {
self
.background (
GeometryReader { geometry in
Color.clear
.onChange(of: geometry.size) { newValue in
onLayout(newValue)
}
.onAppear {
onLayout(geometry.size)
}
}
.ignoresSafeArea(.container, edges: .vertical)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,16 @@ - (void)onTabBarMeasuredWithHeight:(NSInteger)height reactTag:(NSNumber *)reactT
}
}

- (void)onLayoutWithSize:(CGSize)size reactTag:(NSNumber *)reactTag {
auto eventEmitter = std::static_pointer_cast<const RNCTabViewEventEmitter>(_eventEmitter);
if (eventEmitter) {
eventEmitter->onNativeLayout(RNCTabViewEventEmitter::OnNativeLayout {
.height = size.height,
.width = size.width
});
}
}

@end

Class<RCTComponentViewProtocol> RNCTabViewCls(void)
Expand Down
24 changes: 9 additions & 15 deletions packages/react-native-bottom-tabs/ios/RCTTabViewViewManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,10 @@
@interface RCTTabView : RCTViewManager <TabViewProviderDelegate>
@end

@implementation RCTTabView {
uint16_t _coalescingKey;
}
@implementation RCTTabView

RCT_EXPORT_MODULE(RNCTabView)

- (instancetype)init
{
self = [super init];
if (self) {
_coalescingKey = 0;
}
return self;
}

RCT_EXPORT_VIEW_PROPERTY(items, NSArray)
RCT_EXPORT_VIEW_PROPERTY(onPageSelected, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onTabLongPress, RCTDirectEventBlock)
Expand All @@ -51,17 +40,22 @@ - (instancetype)init
// MARK: TabViewProviderDelegate

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

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

- (void)onTabBarMeasuredWithHeight:(NSInteger)height reactTag:(NSNumber *)reactTag {
auto event = [[TabBarMeasuredEvent alloc] initWithReactTag:reactTag height:height coalescingKey:_coalescingKey++];
auto event = [[TabBarMeasuredEvent alloc] initWithReactTag:reactTag height:height];
[self.bridge.eventDispatcher sendEvent:event];
}

- (void)onLayoutWithSize:(CGSize)size reactTag:(NSNumber *)reactTag {
auto event = [[OnNativeLayoutEvent alloc] initWithReactTag:reactTag size:size];
[self.bridge.eventDispatcher sendEvent:event];
}

Expand Down
9 changes: 5 additions & 4 deletions packages/react-native-bottom-tabs/ios/TabViewImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,17 @@ struct TabViewImpl: View {

var onSelect: (_ key: String) -> Void
var onLongPress: (_ key: String) -> Void
var onLayout: (_ size: CGSize) -> Void
var onTabBarMeasured: (_ height: Int) -> Void

var body: some View {
TabView(selection: $props.selectedPage) {
ForEach(props.children.indices, id: \.self) { index in
renderTabItem(at: index)
}
.measureView(onLayout: { size in
onLayout(size)
})
}
#if !os(tvOS)
.onTabItemEvent({ index, isLongPress in
Expand Down Expand Up @@ -326,13 +330,10 @@ extension View {
) -> some View {
if flag {
self
.ignoresSafeArea(.container, edges: .all)
.frame(idealWidth: frame.width, idealHeight: frame.height)
.ignoresSafeArea(.container, edges: .vertical)
} else {
self
.ignoresSafeArea(.container, edges: .horizontal)
.ignoresSafeArea(.container, edges: .bottom)
.frame(idealWidth: frame.width, idealHeight: frame.height)
}
}

Expand Down
21 changes: 12 additions & 9 deletions packages/react-native-bottom-tabs/ios/TabViewProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import React
import SDWebImage
import SDWebImageSVGCoder

@objc public final class TabInfo: NSObject {
@objc public let key: String
@objc public let title: String
@objc public let badge: String
@objc public let sfSymbol: String
@objc public let activeTintColor: UIColor?
@objc public let hidden: Bool

@objc
@objcMembers
public final class TabInfo: NSObject {
public let key: String
public let title: String
public let badge: String
public let sfSymbol: String
public let activeTintColor: UIColor?
public let hidden: Bool

public init(
key: String,
title: String,
Expand All @@ -35,6 +35,7 @@ import SDWebImageSVGCoder
func onPageSelected(key: String, reactTag: NSNumber?)
func onLongPress(key: String, reactTag: NSNumber?)
func onTabBarMeasured(height: Int, reactTag: NSNumber?)
func onLayout(size: CGSize, reactTag: NSNumber?)
}

@objc public class TabViewProvider: UIView {
Expand Down Expand Up @@ -184,6 +185,8 @@ import SDWebImageSVGCoder
self.delegate?.onPageSelected(key: key, reactTag: self.reactTag)
} onLongPress: { key in
self.delegate?.onLongPress(key: key, reactTag: self.reactTag)
} onLayout: { size in
self.delegate?.onLayout(size: size, reactTag: self.reactTag)
} onTabBarMeasured: { height in
self.delegate?.onTabBarMeasured(height: height, reactTag: self.reactTag)
})
Expand Down
Loading
Loading