Im making an app in React Native, and am looking to have a page that displays the bottom navigation bar but isn't directly on that navigation bar, i.e. it is sort of a child of another page though does not need to be access through the bottom Nav.
However, whenever I take it out of the bottom tab navigator it won't hide the icon, and if it is not added it wont allow me to see the bottom nav when I go to that page.
The code is as follows;
{
History: {
screen: HistoryScreen,
navigationOptions: {
tabBarIcon: ({ focused, tintColor }) =>
<Icon
focused={focused}
color={{ tintColor }}
name="history"
size={20}
zIdex="13"
solid
/>
}
},
Home: {
screen: HomeScreen,
navigationOptions: {
tabBarIcon: ({ focused, tintColor }) =>
<Icon
focused={focused}
color={ Colors.gyroscopicOrgane }
name="home"
size={20}
zIdex="13"
solid
/>
}
},
ConcreteTest: {
screen: ConcreteTestScreen,
navigationOptions: {
tabBarIcon: ({ focused,tintColor }) => <
Icon name="cog"
focused={focused}
color={{ tintColor }}
size={20}
zIdex="13"
solid
/>
}
},
Settings: {
screen: SettingsScreen,
navigationOptions: {
tabBarIcon: ({ }) => {
showIcon: false
}
}
}
},
{
tabBarOptions: {
activeTintColor: "#E66F25",
inactiveTintColor: "#B8BBC4",
showLabel: false
}
}
)
const AppStack = createStackNavigator({
Home: HomeScreen,
History: HistoryScreen,
ConcreteTest: ConcreteTestScreen,
Settings: SettingsScreen,
});
const AuthStack = createStackNavigator({
Launch: LaunchScreen,
Login: LoginScreen,
SignUp: SignUpScreen
});
export default createAppContainer(
createSwitchNavigator(
{
Loading: LoadingScreen,
Launch: LaunchScreen,
Settings: SettingsScreen,
App: AppTabNavigator,
Features: AppStack,
Auth: AuthStack
},
{
initialRouteName: "Loading"
}
)
)
It might be helpful to attach a screenshot of your layout. Try positioning your element absolutely (position: absolute) and then using top: left: bottom: right: to align it. If you need it to display conditionally, try setting a variable elementVar = null; and then if (needs to be displayed) {elementVar = YOUR_ELEMENT_CONTENT} then simply use {elementVar} in your render(return()) function.
Related
I am using React Native Tab navigator and I am trying to have my Screen route names as header but with no luck. The fact that the screens are rendered inside the Tab Navigator makes it so their headers are ignored. I have tried setting headerShown=true and many other things with no luck.
This is part of my App.js code:
const AppStack = createStackNavigator({
Navigation: {
screen: NavigationScreen,
navigationOptions: {
}
},
Route: {
screen: RouteScreen,
navigationOptions: {
// headerShown: false
headerTitle: 'TestTitle'
}
},
Confirm: {
screen: ConfirmScreen,
navigationOptions: {
// headerShown: false
headerTitle: 'TestTitle'
}
},
Find: {
screen: FindScreen,
navigationOptions: {
// headerShown: false
headerTitle: 'TestTitle'
}
},
Offer: {
screen: OfferScreen,
navigationOptions: {
// headerShown: false
headerTitle: 'TestTitle'
}
},
and here is my Navigation Screen code:
export default function NavigationScreen( {navigation}) {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ color, size }) => {
const icons = {
Home: 'home',
Profile: 'account',
Offer: 'car-hatchback',
Find: 'magnify'
};
return (
<MaterialCommunityIcons
name={icons[route.name]}
color='#E9446A'
size={30}
/>
);
},
})}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={HomeTabScreen} />
<Tab.Screen name="My Rides" children={()=><MyRidesScreen navigation={navigation}/>} />
<Tab.Screen name="Offer" children={()=><OfferScreen navigation={navigation}/>} />
<Tab.Screen name="Find" children={()=><FindScreen navigation={navigation}/>} />
</Tab.Navigator>
</NavigationContainer>
);
}
Any change attempted to the Tab.Screen routes via options is rendered on the bottom tab Names and not the screen header, as the parent screen is always Navigation Screen
I defined a routes.js file where all the routes from my Drawer navigation are created. This works fine except in one instance. I have one StackNavigator like so:
const ChatScreens = createStackNavigator(
{
Chat: {
screen: Chat,
},
Transactions: {
screen: Transactions,
navigationOptions: {
headerLeft: (
<MaterialIcons
name="chat"
size={24}
style={{ color: colors.BLACK, marginLeft: 10 }}
onPress={() => navigation.popToTop()} //not working
/>
),
}
},
Logout: {
screen: AuthLoadingScreen,
},
},
{
mode: 'card',
initialRouteName: 'Chat',
navigationOptions: {
drawerIcon: getDrawerItemIcon('chat'),
}
},
);
This code, if removed would render a default "< Back" arrow that works just fine. However, I want to use the icon. I tried adding said navigationOptions inside my Transactions.js file but they just get ignored. The only way they take effect is by adding this inside my routes.js the problem, is that there is no navigation within the said file so, of course, I get the Can't find variable: navigation error.
I attempted to change this line to NavigationActions but it won't work either if I do .navigate() or .back(). The truth is that I know the best place for this navigationOptions is within my Transactions file but I can't figure out why it's not working over there.
So either could you a) help me understand why it won't work under Transactions.js or b) help me make the navigation work inside my routes.js for this case?
Just FYI, towards the bottom of my routes.js I have my DrawerNavigation created successfully the following way:
export default Drawer = createAppContainer(
createDrawerNavigator({
Chat:{
screen: ChatScreens,
},
Info:{
screen: InfoScreens,
},
User: {
screen: UserScreens,
},
Feedback: {
screen: FeedbackScreens,
navigationOptions: {
drawerLabel: <Hidden />
}
}
},
{
initialRouteName: 'Chat',
contentComponent: DrawerContent,
contentOptions: {
activeTintColor: colors.TURQUOISE,
itemsContainerStyle: {
marginVertical: 0,
},
iconContainerStyle: {
opacity: 1
}
}
})
);
If you want to use navigation in navigationOptions, you need to use the method like navigationOptions = ({ navigation, navigationOptions }) => {}
For example,
class A extends Component {
static navigationOptions = ({ navigation }) => {
return {
headerLeft: (
<MaterialIcons
name="chat"
size={24}
style={{ color: colors.BLACK, marginLeft: 10 }}
onPress={() => navigation.popToTop()}
/>
),
}
};
};
...
But you try to use navigation not defined.
onPress={() => navigation.popToTop()} // navigation is not defined
I have simple createBottomTabNavigator and one of it's tabs is createStackNavigator and inside this stack I have one screen which I want it to over lap the tab bar. I tried use tabBarVisible: false on this screen but no luck there.
Code:
const BookingsStack = createStackNavigator({
Commutes: {
screen: Commutes,
navigationOptions: {
title: "Commutes",
header: null,
}
},
Tickets: {
screen: Tickets,
navigationOptions: {
title: "Tickets",
header: null,
tabBarVisible: false
}
}
});
export const MainNav = createBottomTabNavigator({
Current: {
screen: Current,
navigationOptions: {
title: "Current",
tabBarIcon: ({ tintColor }) => (
<IconIO name="ios-bus" size={scale(20)} color={tintColor} />
)
}
},
BookingsStack: {
screen: BookingsStack,
navigationOptions: {
title: "Commutes",
tabBarIcon: ({ tintColor }) => (
<IconSL name="layers" size={scale(20)} color={tintColor} />
)
}
}
}
As given in the navigation document:
If we want to hide the tab bar when we navigate from the feed home to a details screen without shuffling navigators, we cannot set the tabBarVisible: false configuration in navigationOptions on DetailsScreen, because those options will only apply to the FeedStack. Instead, we can do the following:
const FeedStack = createStackNavigator({ FeedHome: FeedScreen,
Details: DetailsScreen, });
FeedStack.navigationOptions = ({ navigation }) => { let
tabBarVisible = true; if (navigation.state.index > 0) {
tabBarVisible = false; }
return {
tabBarVisible,
}; };
I found a solution in the react-navigation docs - the implementation look like this:
const ChildMainNav = createBottomTabNavigator({
Current: {
screen: Current,
navigationOptions: {
title: "Current",
tabBarIcon: ({ tintColor }) => (
<IconIO name="ios-bus" size={scale(20)} color={tintColor} />
)
}
},
Commutes: {
screen: Commutes,
navigationOptions: {
title: "Commutes",
tabBarIcon: ({ tintColor }) => (
<IconSL name="layers" size={scale(20)} color={tintColor} />
)
}
}
}
export const MainNav = createStackNavigator({
ChildMainNav: {
screen: ChildMainNav,
navigationOptions: {
header: null
}
},
// overlap screens
Tickets: {
screen: Tickets,
navigationOptions: {
title: "Tickets",
header: null,
tabBarVisible: false
}
}
});
The idea is to add the Tab navigator into Stack navigator and add in this stack any other screens you want to have different navigationOptions to overlap the ones in your Tab.
Link to docs under:
A tab navigator contains a stack and you want to hide the tab bar on specific screens
So this is the case. I have let's say login screen which is tab based, one tab is login and other one is register. I also have "Forgot password" button. So when I press forgot password button I want to go to a single screen which does not contain tab navigation and has that "back" button in it's header.
This is my Navigator if this is helps in any way:
const LoginStack = createStackNavigator({
Login: LoginScreen,
});
LoginStack.navigationOptions = {
tabBarLabel: 'Login',
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={"login"}
/>
),
tabBarOptions: {
activeTintColor: "black",
}
};
const RegisterStack = createStackNavigator({
Register: RegisterScreen,
});
RegisterStack.navigationOptions = {
tabBarLabel: 'Register',
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={"account-plus"}
/>
),
tabBarOptions: {
activeTintColor: "black",
}
};
export default createBottomTabNavigator({
LoginStack,
RegisterStack,
});
If you need any more info, please comment.
Thanks!
Instead of directly exporting createBottomTabNavigator, you create tabs then follow as below
const Tabs = createBottomTabNavigator({
LoginStack,
RegisterStack,
});
const AppNavigator = createStackNavigator({
Tabs,
ForgotPassword: {
screen: ForgotPassword,
}
}) //fixed brackets
export AppNavigator
When I am on settings screen, I see that the Review Icon (favorite) is missing. It shows when I am back on Review screen. Why is that happening. See the screenshot I took. Pasting relevant code snippet from my project for reference.
const MainNavigator = TabNavigator({
map: { screen: MapScreen },
deck: { screen: DeckScreen },
review: {
screen: StackNavigator({
review: { screen: ReviewScreen },
settings: { screen: SettingsScreen }
})
}
}, {
tabBarPosition: 'bottom',
tabBarOptions: {
labelStyle: { fontSize: 12 }
}
});
class ReviewScreen extends Component {
static navigationOptions = props => {
const {navigation} = props;
const {navigate} = navigation;
return {
tabBarIcon: ({ tintColor }) => {
return <Icon name="favorite" size={30} color={tintColor} />
},
headerTitle: 'Review Jobs',
headerRight: (
<Button
title="Settings"
onPress={() => navigate('settings')}
backgroundColor="rgba(0,0,0,0)"
color="rgba(0, 122, 255, 1)"
/>
)
}
}
Leads here is appreciated.
There is an issue with your code, since you're setting every icon's tintColor in the static navigationOptions as
tabBarIcon: ({tintColor}) => {
return <Icon name="favorite" size={30} color={tintColor}/>
}
and there is none for the Settings Screen, which also expects an Icon as it is inside the TabNavigator, therefore null is being rendered there.
Therefore you need to set the navigationOptions in the Settings Screen as
static navigationOptions = props => {
const {navigation} = props;
const {navigate} = navigation;
return {
tabBarIcon: ({tintColor}) => {
return <Icon name="favorite" size={30} color={tintColor}/>
}
}
}
or you may add the default icons in your App.js navigation file as
screen: TabNavigator({
map: { screen: MapScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Icon name="favorite" size={30} color={tintColor}/>
)
}
},
// ....so on
Hope it helps!