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/perfect-onions-reply.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'react-native-bottom-tabs': patch
---

feat: add useBottomTabBarHeight() hook
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.5.2):
- react-native-bottom-tabs (0.6.0):
- 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.5.2)
- react-native-bottom-tabs/common (= 0.6.0)
- 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.5.2):
- react-native-bottom-tabs/common (0.6.0):
- 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: 402d19b4a55e6e17c78736a9dd2592cd9864881e
react-native-bottom-tabs: c17ddaf86c160134349c6325e020c1f38ee5f743
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: 055f92ad73f8c8600a93f0e25ac0b2344c3b07e6
Yoga: aa3df615739504eebb91925fc9c58b4922ea9a08

PODFILE CHECKSUM: 1c1dbca3e400ef935aa9a150cb2dcb58fb8c4536

COCOAPODS: 1.15.2
COCOAPODS: 1.14.3
75 changes: 75 additions & 0 deletions apps/example/src/Components/MusicControl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import * as React from 'react';
import { View, Text, StyleSheet } from 'react-native';

type MusicControlProps = {
bottomOffset: number;
};

export const MusicControl: React.FC<MusicControlProps> = ({ bottomOffset }) => {
return (
<View
style={[
styles.musicControlContainer,
{
bottom: bottomOffset + 10,
},
]}
>
<View style={styles.musicControlContent}>
<View style={styles.songInfo}>
<Text style={styles.songTitle} numberOfLines={1}>
Currently Playing Song
</Text>
</View>
<View style={styles.controls}>
<Text style={styles.controlButton}>⏸</Text>
<Text style={styles.controlButton}>⏭</Text>
</View>
</View>
</View>
);
};

const styles = StyleSheet.create({
musicControlContainer: {
position: 'absolute',
left: 15,
right: 15,
borderRadius: 18,
height: 55,
backgroundColor: '#fff',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 4,
},
shadowOpacity: 0.25,
shadowRadius: 5,
elevation: 8,
},
musicControlContent: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 16,
paddingVertical: 8,
},
songInfo: {
flex: 1,
marginRight: 16,
},
songTitle: {
fontSize: 14,
fontWeight: '600',
color: '#000',
},
controls: {
flexDirection: 'row',
alignItems: 'center',
},
controlButton: {
fontSize: 24,
paddingHorizontal: 12,
color: '#000',
},
});
4 changes: 4 additions & 0 deletions apps/example/src/Screens/Contacts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
Text,
View,
} from 'react-native';
import { useBottomTabBarHeight } from 'react-native-bottom-tabs';
import { MusicControl } from '../Components/MusicControl';

type Item = { name: string; number: number };

Expand Down Expand Up @@ -97,6 +99,7 @@ export function Contacts({ query, ...rest }: Props) {
console.log(Platform.OS, ' Rendering Contacts');
const renderItem = ({ item }: { item: Item }) => <ContactItem item={item} />;

const tabBarHeight = useBottomTabBarHeight();
const ref = React.useRef<FlatList>(null);
useScrollToTop(ref);

Expand All @@ -117,6 +120,7 @@ export function Contacts({ query, ...rest }: Props) {
renderItem={renderItem}
ItemSeparatorComponent={ItemSeparator}
/>
<MusicControl bottomOffset={tabBarHeight} />
</SafeAreaView>
);
}
Expand Down
35 changes: 35 additions & 0 deletions docs/docs/docs/guides/usage-with-react-navigation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,38 @@ React.useEffect(() => {
return unsubscribe;
}, [navigation]);
```

### Hooks

`useBottomTabBarHeight`

This hook returns the height of the bottom tab bar. This is useful when you want to place a component above the tab bar on iOS. It's not needed to offset the content of the screen as the navigator does it automatically.

```tsx
import { useBottomTabBarHeight } from 'react-native-bottom-tabs';

function MyComponent() {
const tabBarHeight = useBottomTabBarHeight();

return (
<ScrollView>
{/* Content */}
<View style={{ bottom: tabBarHeight }} />
</ScrollView>
);
}
```

Alternatively, you can use the `BottomTabBarHeightContext` directly if you are using a class component or need it in a reusable component that can be used outside the bottom tab navigator:

```tsx
import { BottomTabBarHeightContext } from 'react-native-bottom-tabs';

// ...

<BottomTabBarHeightContext.Consumer>
{tabBarHeight => (
/* render something */
)}
</BottomTabBarHeightContext.Consumer>
```
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ import React
private var key: NSString
@objc public var viewTag: NSNumber
@objc public var coalescingKey: UInt16

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

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

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

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

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

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

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

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

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

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

@objc public func arguments() -> [Any] {
return [
viewTag,
RCTNormalizeInputEventName(eventName) ?? eventName,
[
"height": height
]
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@ protocol RCTEvent {}
private var key: NSString
@objc public var viewTag: NSNumber
@objc public var coalescingKey: UInt16

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

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

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

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

@objc public func arguments() -> [Any] {
return [
viewTag,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,15 @@ - (void)onLongPressWithKey:(NSString *)key reactTag:(NSNumber *)reactTag {
}
}

- (void)onTabBarMeasuredWithHeight:(NSInteger)height reactTag:(NSNumber *)reactTag {
auto eventEmitter = std::static_pointer_cast<const RNCTabViewEventEmitter>(_eventEmitter);
if (eventEmitter) {
eventEmitter->onTabBarMeasured(RNCTabViewEventEmitter::OnTabBarMeasured {
.height = (int)height
});
}
}

@end

Class<RCTComponentViewProtocol> RNCTabViewCls(void)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ - (instancetype)init
RCT_EXPORT_VIEW_PROPERTY(items, NSArray)
RCT_EXPORT_VIEW_PROPERTY(onPageSelected, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onTabLongPress, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onTabBarMeasured, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(selectedPage, NSString)
RCT_EXPORT_VIEW_PROPERTY(tabViewStyle, NSString)
RCT_EXPORT_VIEW_PROPERTY(icons, NSArray<RCTImageSource *>);
Expand Down Expand Up @@ -59,6 +60,11 @@ - (void)onPageSelectedWithKey:(NSString *)key reactTag:(NSNumber *)reactTag {
[self.bridge.eventDispatcher sendEvent:event];
}

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

- (UIView *)view
{
return [[TabViewProvider alloc] initWithDelegate:self];
Expand Down
8 changes: 6 additions & 2 deletions packages/react-native-bottom-tabs/ios/TabViewImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@ struct RepresentableView: UIViewRepresentable {
*/
struct TabViewImpl: View {
@ObservedObject var props: TabViewProps
var onSelect: (_ key: String) -> Void
var onLongPress: (_ key: String) -> Void
@Weak var tabBar: UITabBar?

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

var body: some View {
TabView(selection: $props.selectedPage) {
Expand All @@ -83,6 +84,9 @@ struct TabViewImpl: View {
#endif
.introspectTabView(closure: { tabController in
tabBar = tabController.tabBar
onTabBarMeasured(
Int(tabController.tabBar.frame.size.height)
)
})
.configureAppearance(props: props, tabBar: tabBar)
.tintColor(props.selectedActiveTintColor)
Expand Down
Loading
Loading