React Native Navigation To External Tab Within BottomTabBar Screen - react-native

I have an issue where I do not know how to navigate from a screen in a bottom tab bar that looks like this:
default: createBottomTabNavigator(
{
Home: {
screen: HomeScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <Ionicons name="ios-home" size={24} color={tintColor} />
}
},
Message: {
screen: MessageScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <Ionicons name="ios-chatboxes" size={24} color={tintColor} />,
OtherUser: { screen: OtherUserScreen }
}
},
Post: {
screen: PostScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <Ionicons name="ios-add-circle" size={48} color={"#4cdd75"} style={{
shadowColor: "#4cdd75",
shadowOffset: {
width: 0,
height: 0
},
shadowRadius: 10,
shadowOpacity: 0.3
}} />
}
},
Notification: {
screen: NotificationScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <Ionicons name="ios-notifications" size={24} color={tintColor} />
}
},
Profile: {
screen: ProfileScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <Ionicons name="ios-person" size={24} color={tintColor} />
}
}
}
With the createSwitchNavigator component looking like this:
export default createAppContainer(
createSwitchNavigator(
{
Loading: LoadingScreen,
App: AppContainer,
Auth: AuthStack,
OtherUser: OtherUserScreen
},
{
initialRouteName: 'Loading'
}
)
);
The AppContainer is the bottom tab navigator screen setup.
Additionally, My navigation from within my message screen looks like this:
const { navigate } = this.props.navigation;
...
onPress={() => navigate('OtherUser')}
From this message screen I want to navigate to the OtherUser screen so that the bottom tab navigator is still shown. Currently, the navigation navigates to the OtherUser screen, but the bottom tab navigator dissapears. And when I try to use the back button code navigation in my OtherUser Screen that looks like this:
onPress={() => navigate("MessageScreen")}
Nothing is shown. Would it be possible in any way to have the navigation from message screen to the other user screen seemless without deleting the bottom tab bar and without adding another component to it?

From what I see, what you're trying to do is wrong.
It makes sense that the bottomBar disappears because you use a SwitchNavigator to navigate between "AppContainer" and "OtherUser".
So the moment you navigate to "OtherUser", you are no longer in a bottomMenu navigation, you are simply in a SwitchNavigator!
To be able to do what you want to do, you should integrate a stackNavigator instead of MessageScreen,
then in this StackNavigator, you integrate your MessageScreen as well as OtherUser
Currently, your navigation seems to be like this:
- Loading
- App
-- bottomTabMenu
-- Home
-- Message
-- Posts
-- Notifications
-- Profile
- Auth
- OtherUser
So as you see, when you go to "OtherUser" you are not in a BottomMenu navigation anymore, besides that, you can't go back because actually, to be able to go back with a back button, you need to be in a stack navigation.
So if you want to be able to go to the user profile from your messageScreen, you need to wrap it in a navigation stack, and integrate this stack into your bottomMenu.
Your navigation should then look something like this:
- Loading
- App
-- bottomTabMenu
-- Home
-- Message
-- Stack Navigation
-- Message Screen (defaultRoute)
-- OtherUser Screen
-- Posts
-- Notifications
-- Profile
- Auth
So your code will be something like this:
const MessageStack = createStackNavigator(
{
Message: MessageScreen,
OtherUser: OtherUserScreen
},
{
initialRouteName: "Message"
}
)
default: createBottomTabNavigator(
{
...
Message: {
screen: MessageStack,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <Ionicons name="ios-chatboxes" size={24} color={tintColor} />,
OtherUser: { screen: OtherUserScreen } //Delete this line, the navigationOptions are only used to define styles or behaviors on the navigation.
}
},
...
}
I hope I understood the question and that this answer will help you!
Viktor

Related

Is there a option to disable tabbar buttons

In my react native app, I have a router component which uses react-navigation-material-bottom-tabs.
In that component I have created it like this.
const tabNavigator = createMaterialBottomTabNavigator({
home: {
screen: Home,
navigationOptions: ({ navigation }) => ({
title: ''
})
},
createCampaign: {
screen: CreateCampaign,
navigationOptions: ({ navigation }) => ({
title: '',
tabBarVisible: false
})
},
settings: {
screen: AllSettings,
navigationOptions: ({ navigation }) => ({
title: ''
})
}
});
This is working fine. But I want to disable some tabs of this bar under some conditions. As example, if the profile hasn't been approved, disable the tab to settings. Is there any way to do this in my screens?(Better if it's not in the router because I can't send a API request in router). How can I access tabBar options in screens? How to disable tabs? Please help.
For Version 5.x there's a new way to do it.
<Tabs.Screen
name="Chat"
component={Chat}
listeners={{
tabPress: e => {
// Prevent default action
e.preventDefault();
},
}}
/>
Here's the reference link to the docs: https://reactnavigation.org/docs/navigation-events/
What are you using for global state management inside your app, please store the status weather profile is approved or not inside your global state. Then you can override tabBarOnPress to check if user is approved and perform the actions accordingly, code snippet below.
const Tab_Navigator = createBottomTabNavigator({
First:{
screen: First,
},
Second:{
screen: Second,
},
Third:{
screen: Third,
}
}, defaultNavigationOptions: ({ navigation }) => ({
tabBarOnPress: ({ navigation, defaultHandler }) => {
if (
navigation.state.routeName === "Second" ||
navigation.state.routeName === "Third"
) {
return null;
}
defaultHandler();
},})
You can try with tabBarComponent props available in the second parameter for createBottomTabNavigator.
You can enable or disable button as you like but please look at the note below.
I used native base Footer, you can use your preferred components.
import { Footer, FooterTab } from 'native-base'
const HomeScreen = createBottomTabNavigator(
{
First:{
screen: First,
},
Second:{
screen: Second,
},
Third:{
screen: Third,
}
},
{
tabBarComponent: props => {
return (
<Footer>
<FooterTab>
<Button
vertical
active={props.navigation.state.index === 0}
onPress={() => props.navigation.navigate(actions.First)}
>
</Button>
<Button
vertical
active={props.navigation.state.index === 1}
onPress={() => props.navigation.navigate(actions.Second)}
>
</Button>
<Button
vertical
active={props.navigation.state.index === 2}
onPress={() => props.navigation.navigate(actions.Third)}
>
</Button>
</FooterTab>
</Footer>
)
}
}
)
Note: If you want to dynamically change your buttons(tab bars elements) you can not do it as these buttons are assigned on the basis of the index.
I am Working on the old Project there used React-Navigation version 4.
The Solution that worked for me is follow ....
Home: {
screen: HomeStack,
navigationOptions: {
tabBarOnPress:()=>{
return null;
},
tabBarLabel: "Home",
tabBarOptions: {
activeTintColor: "#455BE0",
inactiveTintColor: "gray",
},
tabBarIcon: ({ tintColor }) => (
<Image
style={{ height: 25, width: 25, tintColor: tintColor, marginTop: 10 }}
source={require("./src/assets/home.png")}
/>
),
},
},
You can check in the navigationOptions added tabBarOnPress which return value is null.
This solution work for me Hope work for you also.
You can overwrite tabBarButton​ using Pressable or Button component and add a conditional in order to disable the button. Something like this :
<Stack.Screen
name="YourScreen"
options={{
tabBarButton: (props) => (
<Pressable
{...props}
isDisabled={conditional ? true : false}
/>
),
}}
component={YourComponent}
/>

Navigation drawer is not opening and toggleDrawer not found

Trying to create drawer using React-Navigation.
Using React Native 0.59, Installed React-Navigation 3.x, has done linking react-native link react-native-gesture-handler.
Create routes using React-Navigation, called Route.js:
const Drawer = createDrawerNavigator(
{
Settings: {
screen: HomeScene,
navigationOptions: {
title: 'Home',
drawerIcon: () => (
<Icon name="home" style={{ color: colors.white, fontSize: 24 }} type="Ionicons" />
)
}
}
},
{
contentComponent: props => <GlobalSideMenu {...props} />
}
);
const AppNavigator = createStackNavigator(
{
Home: {
screen: HomeScene,
navigationOptions: {
header: null
}
},
Drawer: {
screen: Drawer,
navigationOptions: {
header: null
}
}
},
{
initialRouteName: 'Home'
}
);
export default createAppContainer(AppNavigator);
Then in the header, drawer icon:
<Button icon transparent onPress={() => this.props.navigation.toggleDrawer()}>
<Icon name={icon('menu')} type="Ionicons" style={styles.menuColor} />
</Button>
It gives me error : toggleDrawer() is undefined.
Then I change it to :
this.props.navigation.dispatch(DrawerActions.toggleDrawer());
Now, there is no error, but the drawer is not opening.
This is usually the case if you are attempting to open the drawer from outside the drawer navigator's set of screens.
this.props.navigation.toggleDrawer is only defined if you are in Settings, which I guess is not the case.
You can either rearrange the navigation so that the drawer is present on the screen you are calling toggleDrawer from, or you can navigate to Settings first.
<Button
icon
transparent
onPress={() => {
this.props.navigation.navigate('Settings');
this.props.navigation.dispatch(DrawerActions.openDrawer());
}}
>
<Icon name={icon('menu')} type="Ionicons" style={styles.menuColor} />
</Button>
Here is an example to clarify.

Uber-like Drawer navigation in React Native app

I'm trying to figure out how to implement navigation in React Native app using react-navigation to make it similar to Uber app.
I'd like to use Drawer which contains a menu items like Settings, Profile etc. Click on each item should open a modal with navigation Stack with arrow left or cross icon button on the top (header) to close stack and back to main screen. When modal with navigation stack is opened I'd like to disable drawer.
Is this possible to achieve with react-navigation?
Yes react navigation drawer accepts arbitrary react components as content. You can see an example by running https://expo.io/#react-navigation/NavigationPlayground on your phone.
Some example code from https://github.com/react-navigation/react-navigation/blob/master/examples/NavigationPlayground/src/Drawer.tsx
const InboxStack = createStackNavigator(
{
Email: { screen: EmailScreen },
Inbox: { screen: InboxScreen },
},
{
navigationOptions: {
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="move-to-inbox"
size={24}
style={{ color: tintColor } as StyleProp<TextStyle>}
/>
),
drawerLabel: 'Inbox',
},
}
);
const DraftsStack = createStackNavigator(
{
Drafts: { screen: DraftsScreen },
Email: { screen: EmailScreen },
},
{
navigationOptions: {
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="drafts"
size={24}
style={{ color: tintColor } as StyleProp<TextStyle>}
/>
),
drawerLabel: 'Drafts',
},
}
);
const DrawerExample = createDrawerNavigator(
{
Drafts: {
path: '/sent',
screen: DraftsStack,
},
Inbox: {
path: '/',
screen: InboxStack,
},
},
{
contentOptions: {
activeTintColor: '#e91e63',
},
initialRouteName: 'Drafts',
}
);

Tab Navigator On focussed

I have a TabNavigator
const Tabs = TabNavigator({
Test: {
screen: SCA,
navigationOptions: () => ({
title: 'Home',
tabBarIcon: ({ tintColor }) => {
return (
<FAIcon
name='screen1'
size={25}
color={tintColor}
/>
);
}
})
},
Screen2: {
screen: SCB,
navigationOptions: () => ({
title: 'screen2',
tabBarIcon: ({ tintColor }) => {
return (
<MIcon
name='account-circle'
size={25}
color={tintColor}
/>
);
}
})
},
screen3: {
screen: MYSCREEN,
navigationOptions: () => ({
title: 'dd',
tabBarIcon: ({ tintColor }) => {
return (
<MIcon
name='account-circle'
size={25}
color={tintColor}
/>
);
}
})
}
}, {
tabBarPosition: 'top',
tabBarOptions: {
showIcon: true,
showLabel: true,
inactiveTintColor: Colors.blue,
activeTintColor: Colors.redColor,
pressColor: Colors.redColor,
indicatorStyle: { backgroundColor: Colors.redColor },
style: {
backgroundColor: Colors.white
}
}
});
Basically I have tab navigator with 3 tabs. Whenever screen3 is focussed via tab button press or by swiping how can I get to know in MYSCREEN that this screen is focussed again.(Screen looks similar to playstore app with selecting screen on tab as well as swiping)
Class MYSCREEN extends React.Component{
//some function like on onfocus?
}
I tried searching it showed onFocusComponent will work but it didn't.
What should I do?
Since you are using react-navigation you can use listeners on the navigation lifecycle events. https://reactnavigation.org/docs/en/navigation-prop.html#addlistener-subscribe-to-updates-to-navigation-lifecycle
There are four events you can subscribe to:
willFocus - the screen will focus
didFocus - the screen focused (if there was a transition, the transition completed)
willBlur - the screen will be unfocused
didBlur - the screen unfocused (if there was a transition, the transition completed)
You can subscribe to as many of them as you want. Here is an example of using didFocus. You could easily replicate this for all that you require.
So in each of the screens of your TabNavigator, you can add the following:
componentDidMount () {
// add listener
this.didFocusSubscription = this.props.navigation.addListener('didFocus', this.didFocusAction);
}
componentWillUmount () {
// remove listener
this.didFocusSubscription.remove();
}
didFocusAction = () => {
// do things here when the screen focuses
}
You can use withNavigationFocus HOC which will add isFocused prop to your screen component's props then catch that prop in getDerivedStateFromProps method and check if isFocused is trueand then return a new state so that the component will render again.

Ripple effect on TabBarBottom

How to add ripple animation when a tabs is clicked in TabBarBottom. I want ripple effect just like Youtube app
You can use Screen's Navigation Options to add desired styled tabBarIcon
tabBarIcon
React Element or a function that given { focused: boolean, tintColor:
string } returns a React.Element, to display in tab bar
tabBarLabel
Title string of a tab displayed in the tab bar or React Element or a
function that given { focused: boolean, tintColor: string } returns
a React.Element, to display in tab bar. When undefined, scene title
is used. To hide, see tabBarOptions.showLabel in the previous
section.
tabBarOnPress
Callback to handle tap events; arguments are the scene: { route,
index } that was tapped and a jumpToIndex method that can perform
the navigation for you.
Example
const MyApp = TabNavigator({
Home: {
screen: MyHomeScreen,
navigationOptions: ({navigation}) => ({
tabBarIcon: ({focuced, tintColor}) => (
<MyCustomIcon focuced={focuced} tintColor={tintColor} name="Home" />
)
})
},
Notifications: {
screen: MyNotificationsScreen,
navigationOptions: ({navigation}) => ({
tabBarIcon: ({focuced, tintColor}) => (
<MyCustomIcon focuced={focuced} tintColor={tintColor} name="Notifications" />
)
})
},
});