How to display a bottom sheet from React navigation BottomTabNavigator?
I want to display a reanimated-bottom-sheet when I click the tabBarIcon (maybe such as button adding in picture) instead of a component.
I'm using
<Tab.Screen
name={Name.name_add_application}
component={Add}
options={{
tabBarIcon: ({focused}) => (
<Image source={TK_Add} resizeMode="contain" style={styles.addBtn} />
),
tabBarButton: props => <CustomTabButton {...props} />,
}}
listeners={({navigation}) => ({
tabPress: e => {
e.preventDefault();
navigation.navigate('CreateNew');
},
})}
/>
in const Tab = createBottomTabNavigator();
and
<MainStack.Group
screenOptions={{
headerShown: false,
cardStyle: {backgroundColor: 'rgba(0, 0, 0, 0)'},
cardOverlayEnabled: true,
cardStyleInterpolator: ({current: {progress}}) => ({
cardStyle: {
opacity: progress.interpolate({
inputRange: [0, 0.5, 0.9, 1],
outputRange: [0, 0.25, 0.7, 1],
}),
},
overlayStyle: {
opacity: progress.interpolate({
inputRange: [0, 0.5],
outputRange: [0, 0.25],
extrapolate: 'clamp',
}),
},
}),
}}
mode="modal">
<MainStack.Screen
name="CreateNew"
component={CreateNew}
options={{
animationEnabled: true,
presentation: 'transparentModal',
}}
/>
</MainStack.Group>
in const MainStack = createStackNavigator();
to open a Modal component.
But it have a little bit lag, show a white background for about 0.01s and can't scroll (I don't want to use this method anymore).
This is my solution
function MyTabBar({ state, descriptors, navigation }) {
const tabRef = React.createRef();
const fall = new Animated.Value(1);
const renderInner = () => (
<View style={styles.panel}>{/* ButtomSheet body */}</View>
);
const renderHeader = () => (
<View style={styles.header}>{/* ButtomSheet header */}</View>
);
return (
<View style={{ flexDirection: "row" }}>
<BottomSheet
ref={tabRef}
snapPoints={[CONST.HEIGHT * 0.5, 0]}
renderContent={renderInner}
renderHeader={renderHeader}
initialSnap={1}
callbackNode={fall}
enabledGestureInteraction={true}
/>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
// const label =
// options.tabBarLabel !== undefined
// ? options.tabBarLabel
// : options.title !== undefined
// ? options.title
// : route.name;
const isFocused = state.index === index;
const onPress = () => {
switch (index) {
// add button's case ( which I want to show bottom sheet)
case 2:
tabRef.current.snapTo(0);
break;
default:
const event = navigation.emit({
type: "tabPress",
target: route.key,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
break;
}
};
const onLongPress = () => {
navigation.emit({
type: "tabLongPress",
target: route.key,
});
};
const TabIcon = () => {
// custom your tab
};
return (
<Pressable
accessibilityRole="button"
accessibilityState={isFocused ? { selected: true } : {}}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID}
onPress={onPress}
onLongPress={onLongPress}
style={{
flex: 1,
alignItems: "center",
backgroundColor: "#fff",
}}
>
<TabIcon />
{/* {label} */}
</Pressable>
);
})}
</View>
);
}
in const Tab = createBottomTabNavigator();
<Tab.Navigator
tabBar={props => <MyTabBar {...props} />}
screenOptions={{headerShown: false}}>
<Tab.Screen name={/* screen name */} component={/* compo */} />
{/* more screens */}
</Tab.Navigator>