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!
Related
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.
I am trying to make a project in react native using expo.
I have a switch navigation for login. After login I have a drawer navigation that contains separate stack navigation. For each screen I want to hide few menus from drawer navigation based on user permissions as the application will be used by admin, employee, manager etc.
Or is there any other way to create a dynamic drawer navigation based on my requirement with menu fetched from database according to user permission?
Drawer navigation should be rendered based on user type after login.
Here is my code snippet for drawer navigation:
const DrawerNav = createDrawerNavigator({
HomeScreen: {
screen: createStackNavigator({
HomeScreen: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => {
return {
title: "Dashboard",
headerLeft: (
<Ionicons
name="md-menu"
size={32}
color="white"
style={{ paddingLeft: 20 }}
onPress={() => navigation.toggleDrawer()}
/>
),
headerStyle: {
backgroundColor: "#B00020"
},
headerTintColor: "#fff",
headerTitleStyle: {
fontWeight: "bold"
}
};
}
}
}),
navigationOptions: ({ navigation }) => ({
drawerLabel: "Dashboard",
drawerIcon: () => <Ionicons name="md-home" size={28} color="#B00020" />
})
},
UserlistDetails: {
name: UserlistDetails,
screen: createStackNavigator({
UserlistDetails: {
screen: UserlistDetails,
navigationOptions: ({ navigation }) => {
return {
title: "User Accnt Details",
headerLeft: (
<Ionicons
name="md-menu"
size={32}
color="white"
style={{ paddingLeft: 20 }}
onPress={() => navigation.toggleDrawer()}
/>
),
headerStyle: {
backgroundColor: "#B00020"
},
headerTintColor: "#fff",
headerTitleStyle: {
fontWeight: "bold"
}
};
}
},
CreateNewUser: {
screen: CreateNewUser,
navigationOptions: ({ navigation }) => {
return {
title: "Create New User",
headerStyle: { backgroundColor: "#B00020" },
headerTintColor: "#fff",
headerTitleStyle: { fontWeight: "bold" }
};
}
}
}),
navigationOptions: ({ navigation }) => ({
drawerLabel: "User Accnt Details",
drawerIcon: () => <Ionicons name="md-person" size={28} color="#B00020" />
})
}
});
const StackNav = createStackNavigator(
{ Dashboard: DrawerNav },
{
defaultNavigationOptions: ({ navigation }) => {
return { header: null };
}
}
);
const Navigation = createAppContainer(StackNav);
export default class Home extends React.Component {
static navigationOptions = { header: null };
render() {
return (
<View style={styles.container}>
<Navigation />
</View>
);
}
}
If you check the react navigation docs, it states that one limitation is the lack of ability to have dynamic routes. All routes have to be static and defined at the beginning. See more here:
https://reactnavigation.org/docs/en/limitations.html#targetText=Dynamic%20routes&targetText=React%20Navigation%20does%20not%20currently,can%20do%20this%20using%20params.
I want pass props from component to createBottomTabNavigator via createStackNavigator
const TabsNavigator = createBottomTabNavigator({
'Notification': {
screen: Private,
navigationOptions: () => ({
tabBarIcon:
<Text style={{ color: '#FFFFFF' }}>
3
</Text>
})
}
})
const BaseNavigatorContainer = createAppContainer(
createStackNavigator({
'TABS': { screen: TabsNavigator }
})
);
class BaseNavigator extends Component {
render() {
return (
<BaseNavigatorContainer screenProps={{ BadgeCount: this.state.BadgeCount }} />
)
}
}
export { BaseNavigator };
I want pass this.state.BadgeCount to
3
You can simply pass a connected component as an icon, that will get the badgeCount:
const TabsNavigator = createBottomTabNavigator({
'Notification': {
screen: Private,
navigationOptions: () => ({
tabBarIcon: ({ tintColor }) => (
<TabBarIconWithBadge color={tintColor} />
),
}),
}
})
And your icon component will look:
const TabBarIconWithBadge = props => (
<Icon color={props.color} />
<Text style={...}>{props.badgeCount}</Text>
);
const mapStateToProps = state => {
return {
badgeCount: state.notifications.badgeCount
};
};
export default connect(mapStateToProps)(TabBarIconWithBadge);
I have a variable 'this.state.userName' in a constructor obtained from AsyncStorage which log perfect at constructor. I want it to be rendered in the header of navigation drawer of react-navigation. I am so mush messed up with the flow as i am new to react-native. I already wasted entire day. The result on the header is null or no any text is shown , No any error too.
The callbacks of setState of 'this.setState.userName':
06-15 00:40:22.211 20510 29463 I ReactNativeJS: { userName: 'Ramesh mike' }
I have tried the following structure:
class ScreensSetup extends Component {
toggleDrawer = () => {
this.props.navigationProps.toggleDrawer();
};
constructor(props) {
super(props);
AsyncStorage.getItem('KeyUserName').then(value =>{
this.setState({ userName: value}, () => console.log(this.state) );
});
AsyncStorage.getItem('KeyUserEmail').then(value =>{
this.setState({ userEmail: value });
});
AsyncStorage.getItem('KeyUserProfilePicture').then(value =>{
this.setState({ userProfilePicture: value });
});
}
render() {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity
onPress={this.toggleDrawer}
style={{padding: 15,}}
>
<Icon ios="ios-menu" android="md-menu" size={30} color="white" />
</TouchableOpacity>
</View>
);
}
}
const FirstStackNavigator = createStackNavigator({
First: {
screen: Dashboard,
navigationOptions: ({ navigation }) => ({
title: 'Dashboard',
headerLeft: <ScreensSetup navigationProps={navigation} />,
headerStyle: {
backgroundColor: 'rgb(216,21,88)',
},
headerTintColor: 'white',
}),
},
});
const SecondStackNavigator = createStackNavigator({
Second: {
screen: Workorders,
................
});
const ThirdStackNavigator = createStackNavigator({
Third: {
screen: Projects,
.............
});
const FourthStackNavigator = createStackNavigator({
Fourth: {
screen: Settings,
...............
});
DrawerContent = (props) => {
return (
<View>
<View style={{ backgroundColor: 'rgb(216,21,88)', height: 160,}}>
<Text>{this.state.userName}</Text> //No display of userName
</View>
<DrawerItems {...props} />
</View>
)
}
const DrawerNavigator = createDrawerNavigator(
{
Dashboard: {
//Title
screen: FirstStackNavigator,
navigationOptions: {
drawerLabel: 'Dashboard',
drawerIcon: () => (
<Icon ios="ios-heart" android="md-heart" size={30} color="black" />
),
},
},
Workorders: {
...
},
Projects: {
...
},
Settings: {
...
},
},
{
contentComponent: DrawerContent,
initialRouteName: 'Dashboard',
drawerWidth: 280,
drawerPosition: 'left',
gesturesEnabled: false,
headerMode: 'float',
contentOptions: {
labelStyle: {
color: 'black'
}
}
},
);
const styles = StyleSheet.create({...})
export default DrawerNavigator
You can try the following:
Promise.all([
AsyncStorage.getItem('KeyUserName'),
AsyncStorage.getItem('KeyUserEmail'),
AsyncStorage.getItem('KeyUserProfilePicture')
]).then(
([userName,userEmail,userProfilePicture])=>
this.setState({ userName,userEmail,userProfilePicture })
)
In my React-native project, I am using drawer navigation. I have set the some screen inside the Drawer navigation and some of the screens outside the Drawer navigation.
I have declared a class named HomeDrawer, for this set up. Here's the code of that class.
HomeDrawer.js
class NavigationDrawerStructure extends React.Component {
constructor() {
super();
this.state = {
ModalVisibleStatus: false,
}
};
static navigationOptions = {
header: null ,
};
toggleDrawer = () => {
this.props.navigationProps.toggleDrawer();
};
render() {
return (
<View style={{ flexDirection: 'row', marginLeft:5 }}>
<TouchableOpacity onPress={this.toggleDrawer.bind(this)}>
<Image style={{width:20, height:20, margin:5, justifyContent:'center'}} source={require('../assets/menu.png')} />
</TouchableOpacity>
</View>
);
}
}
const FirstActivity_StackNavigator = createStackNavigator({
First: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => ({
title: 'Home',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />
),
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
ScreenInternal: {
screen: BookDetails,
navigationOptions: ({ navigation }) => ({
title: 'Screen With Navigation Drawer',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const Screen2_StackNavigator = createStackNavigator({
Second: {
screen: CategoryBrowse,
navigationOptions: ({ navigation }) => ({
title: 'Create Note',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const Drawer = createDrawerNavigator({
Screen1: {
screen: FirstActivity_StackNavigator,
navigationOptions: {
drawerLabel: 'Home',
drawerIcon: (
<Icon name='home' size={25}
/>
)
},
},
Screen2: {
screen: Screen2_StackNavigator,
navigationOptions: {
drawerLabel: 'Category',
drawerIcon: (
<Image source={require('../assets/splash.png')}
style={{height:25, width:25,}}
/>
)
},
},
},
{
contentComponent: CustomSidebarMenu,
//Sidebar width
drawerWidth: Dimensions.get('window').width - 130,
},
);
const Drawer2 = createDrawerNavigator({
Screen1: {
screen: FirstActivity_StackNavigator,
navigationOptions: {
drawerLabel: 'Home',
drawerIcon: (
<Icon name='home' size={25}
/>
)
},
},
Screen2: {
screen: Screen2_StackNavigator,
navigationOptions: {
drawerLabel: 'Category',
drawerIcon: (
<Image source={require('../assets/splash.png')}
style={{height:25, width:25,}}
/>
)
},
},
},
{
drawerType: 'back',
drawerPosition: 'right',
drawerWidth: 200,
drawerBackgroundColor: 'orange',
//For the Custom sidebar menu we have to provide our CustomSidebarMenu
contentComponent: CustomSidebarMenu,
//Sidebar width
drawerWidth: Dimensions.get('window').width - 130,
},
);
const DrawerNavigatorExample = createStackNavigator({
Drawer: { screen: Drawer, navigationOptions: { header: null } },
BookDetails: {
screen: BookDetails,
navigationOptions: { title: 'Book Details' },
},
CartPage: {
screen: CartPage,
navigationOptions: { title: 'Cart Page' },
},
},
);
In the above code, you can see that I have an internal screen named 'HomeScreen' and one external screen of drawer named 'BookDetails'. I have also set the navigationOptions title for the screens.
Now, in the HomeScreen I have a click event , by pressing on e element I pass a value and start the external screen 'BookDetails'. Here's the code for that-
<TouchableOpacity style={{flexDirection:'row'}}
onPress={() => this.props.navigation.navigate('BookDetails', {
JSON_ListView_Clicked_Item: item.id,
})}
>
Now, in the BookDetails screen I want to change the navigation header title according to the value I receive from HomeScreen.
Here's my code of the BookDetails Screen-
BookDetails.js
class BookDetails extends Component {
constructor() {
super()
this.state= {
dataSource : [],
isLoading: true,
bookId: '',
responseDetails:'',
loading: true
}
}
async componentDidMount() {
const { navigation } = this.props;
this.focusListener = navigation.addListener("didFocus", () => {
this.getBookDetailsApi();
});
this.setState({
bookId:(
this.props.navigation.state.params.JSON_ListView_Clicked_Item
? this.props.navigation.state.params.JSON_ListView_Clicked_Item
: 'No Value Passed'
)
})
}
async componentWillMount() {
await Font.loadAsync ({
Roboto: require('native-base/Fonts/Roboto.ttf'),
Roboto_medium: require('native-base/Fonts/Roboto_medium.ttf')
});
this.setState({loading:false});
}
getBookDetailsApi() {
const url = 'my url';
return fetch(url, {
method: 'GET',
headers: new Headers({
'Content-Type' : 'application/json',
'app_api_key': APP_API_KEY,
})
})
.then((response)=> response.json() )
.then((responseJson) => {
console.log('####:'+responseJson.nameEnglish)
this.setState({
responseDetails: responseJson,
isLoading: false,
})
})
.catch((Error) => {
console.log(Error)
});
};
}
render() {
if(this.state.loading) {
return(
<Root>
<AppLoading/>
</Root>
);
}
return (
<View style={styles.container}>
<TouchableOpacity
onPress = {()=>{
this.props.navigation.navigate('CartPage')
}}
>
<Text style={styles.title}>Hello Splash</Text>
</TouchableOpacity>
</View>
);
}
}
export default BookDetails;
Now, I need a solution to keep the BookDetails Screen navigation header title dynamic and keep changing it according to the values I receive from HomeScreen. So, it would be very nice if someone give a solution to that.