102 lines
2.8 KiB
TypeScript
102 lines
2.8 KiB
TypeScript
import React, { useEffect, useRef } from 'react';
|
|
import { BottomNavigation } from 'react-native-paper';
|
|
import { Animated, StyleSheet } from 'react-native';
|
|
import {
|
|
CommonActions,
|
|
NavigationHelpers,
|
|
ParamListBase,
|
|
TabNavigationState,
|
|
} from '@react-navigation/native';
|
|
import { EdgeInsets } from 'react-native-safe-area-context';
|
|
import { BottomTabNavigationEventMap } from '@react-navigation/bottom-tabs';
|
|
import { BottomTabDescriptorMap } from '@react-navigation/bottom-tabs/lib/typescript/src/types';
|
|
import { ROUTE } from '../types';
|
|
|
|
const hideableBottomNavigationBarStyles = StyleSheet.create({
|
|
bar: {
|
|
position: 'absolute',
|
|
bottom: 0,
|
|
left: 0,
|
|
right: 0,
|
|
},
|
|
});
|
|
|
|
const HideableBottomNavigationBar = ({
|
|
navigation,
|
|
state,
|
|
descriptors,
|
|
insets,
|
|
visible = true,
|
|
routeCallback,
|
|
}: {
|
|
navigation: NavigationHelpers<ParamListBase, BottomTabNavigationEventMap>;
|
|
state: TabNavigationState<ParamListBase>;
|
|
descriptors: BottomTabDescriptorMap;
|
|
insets: EdgeInsets;
|
|
visible?: boolean;
|
|
routeCallback?: (route: ROUTE) => void;
|
|
}) => {
|
|
const visibleAnim = useRef(new Animated.Value(visible ? 0 : 1)).current;
|
|
|
|
useEffect(() => {
|
|
Animated.timing(visibleAnim, {
|
|
toValue: visible ? 0 : 1,
|
|
duration: visible ? 200 : 150,
|
|
useNativeDriver: true,
|
|
}).start();
|
|
}, [visible, visibleAnim]);
|
|
|
|
return (
|
|
<Animated.View
|
|
style={{
|
|
marginBottom: insets.bottom,
|
|
transform: [
|
|
{
|
|
translateY: visibleAnim.interpolate({
|
|
inputRange: [0, 1],
|
|
outputRange: [0, 80],
|
|
}),
|
|
},
|
|
],
|
|
...hideableBottomNavigationBarStyles.bar,
|
|
}}>
|
|
<BottomNavigation.Bar
|
|
navigationState={state}
|
|
safeAreaInsets={insets}
|
|
onTabPress={({ route, preventDefault }) => {
|
|
const event = navigation.emit({
|
|
type: 'tabPress',
|
|
target: route.key,
|
|
canPreventDefault: true,
|
|
});
|
|
if (event.defaultPrevented) {
|
|
preventDefault();
|
|
} else {
|
|
navigation.dispatch({
|
|
...CommonActions.navigate(route.name, route.params),
|
|
target: state.key,
|
|
});
|
|
if (routeCallback) routeCallback(route.name as ROUTE);
|
|
}
|
|
}}
|
|
renderIcon={({ route, focused, color }) => {
|
|
const { options } = descriptors[route.key];
|
|
if (options.tabBarIcon) {
|
|
return options.tabBarIcon({
|
|
focused,
|
|
color,
|
|
size: 22,
|
|
});
|
|
}
|
|
}}
|
|
getLabelText={({ route }) => {
|
|
const { options } = descriptors[route.key];
|
|
return options.title ?? route.name;
|
|
}}
|
|
/>
|
|
</Animated.View>
|
|
);
|
|
};
|
|
|
|
export default HideableBottomNavigationBar;
|