navigationOptions headerLeft,headerRight and title not working? - react-native

What I want: put a touchable icon left side that will navigate to my drawer navigator once pressed and the title in the middle then in the right side an icon that has future purposes once clicked
What I tried doing:
I tried to put the navigationOptions under the MainScreen it still doesn't work.
This is my code in my AppNavigation.js
const primaryNav = createStackNavigator({
LaunchScreen: { screen: LaunchScreen },
MainScreen: {
screen: MainScreen,
},
}, {
// Default config for all screens
headerMode: 'none',
initialRouteName: 'MainScreen',
navigationOptions: {
headerStyle: styles.header,
title: 'TY, Next',
headerStyle:{
backgroundColor: "Transparent",
marginRight: 20,
marginLeft: 20,
},
headerRight: (
<TouchableOpacity>
<Icon2 name="sc-telegram" color={Colors.red} size={30} />
</TouchableOpacity>
),
headerLeft: (
<TouchableOpacity>
<Icon name="bars" color={Colors.red} size={25}/>
</TouchableOpacity>
),
}
})
Any idea why my code isn't running? There's no title of Ty next not even the 2 icons that I added. I am using igniteCLI for react native.

I made it work by using the following codes in my screen.
static navigationOptions = ({ navigation }) => {
const {state} = navigation;
const {} = state;
return {
headerStyle:{
backgroundColor: "Transparent",
marginRight: 20,
marginLeft: 20,
},
headerLeft: (
<TouchableOpacity>
<Icon name="bars" color={Colors.red} size={25}/>
</TouchableOpacity>
),
headerLeftStyle: styles.drawerIcon,
headerRight: (
<TouchableOpacity>
<Icon2 name="sc-telegram" color={Colors.red} size={30} />
</TouchableOpacity>
),
headerRightStyle: styles.planeIcon,
headerTransparent: true,
};
}

Use Icon instead of Icon2
if you are using version with 3x
defaultNavigationOptions
instead of navigationOptions
headerRight: (
<TouchableOpacity>
//-->I changed here <Icon name="sc-telegram" color={Colors.red} size={30} />
</TouchableOpacity>
),

Because that methods are deprecated in 'navigationOptions'.
headerRight: <SomeElement /> will be removed in a future version.
As like
headerRight: () => <SomeElement />

Related

React-navigation - goBack behaviour in nested navigators (stack inside drawer)

I'm using a stack navigator inside drawer navigator - recently upgraded from v4. Trying to implement custom back button on headerLeft. goBack function on the stack screen is going back on the drawer navigator instead of the stack. I don't know if I'm missing something or if it's a bug on v5. The goBack should go to the previous screen in the stack not the drawer. See the gif below; using the gesture goes back on the stack and the default back button on the header goes back onto the stack too. It's only my custom back button with the problem.
export function BlogsStack({navigation}) {
return (
<Stack.Navigator
initialRouteName={'Blogs'}
screenOptions={{
gestureEnabled: true,
gestureDirection: 'horizontal',
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
headerStyle: {
borderBottomWidth: 0,
elevation: 0,
shadowOpacity: 0,
},
headerTintColor: themeVars.headerTintColor,
headerBackground: () => {
return <HeaderBackground />;
},
}}>
<Stack.Screen
name="Blogs"
component={Blogs}
options={{
title: 'Blogs',
headerTitle: () => (
<View>
<HeaderButton title={'Blogs'} />
</View>
),
headerLeft: () => (
<TouchableOpacity
onPress={() => navigation.toggleDrawer()}
style={drawerStyles.menuIconContainer}>
<FeatherIcon
style={drawerStyles.menuIcon}
name="menu"
size={themeVars.hamburgerIconSize}
color={themeVars.hamburgerIconColor}
/>
</TouchableOpacity>
),
headerRight: () => <View />,
}}
/>
<Stack.Screen
name="BlogSingle"
component={BlogSingle}
options={{
headerTitle: () => (
<View>
<HeaderButton title={'Blog'} />
</View>
),
headerLeft: () => (
<TouchableOpacity
onPress={() => navigation.goBack()}
style={drawerStyles.menuIconContainer}>
<FeatherIcon
style={drawerStyles.menuIcon}
name="chevron-left"
size={themeVars.hamburgerIconSize}
color={themeVars.hamburgerIconColor}
/>
</TouchableOpacity>
),
headerRight: () => <View />,
}}
/>
</Stack.Navigator>
);
}
export class Navigation extends Component {
constructor(props, context) {
super(props, context);
}
render() {
return (
<NavigationContainer ref={navigationRef}>
<AppDrawer.Navigator
initialRouteName={'Home'}
drawerContent={props => <DrawerContent {...props} />}
drawerContentOptions={{
labelStyle: {
fontFamily: themeVars.boldFont,
color: themeVars.primaryColor,
},
activeTintColor: 'black',
activeBackgroundColor: 'black',
inactiveTintColor: 'white',
inactiveBackgroundColor: 'white',
itemStyle: {
marginVertical: 0,
borderWidth: 1,
borderColor: 'red',
margin: 0,
padding: 0,
},
}}>
<AppDrawer.Screen
name="Home"
component={HomeStack}
initialRouteName={'Home'}
options={{
drawerLabel: 'Home ',
drawerIcon: () => (
<FeatherIcon
color={themeVars.primaryColor}
name="home"
size={themeVars.drawerIconSize}
/>
),
}}
/>
<AppDrawer.Screen
initialRouteName="Blogs"
backBehavior="order"
name="Blogs"
component={BlogsStack}
options={{
drawerLabel: 'Blogs ',
drawerIcon: () => (
<FontAwesome5
color={themeVars.primaryColor}
name="wordpress"
size={themeVars.drawerIconSize}
/>
),
}}
/>
</AppDrawer.Navigator>
</NavigationContainer>
);
}
}
I sorted out my issue by following the docs. The issue was that I was passing the wrong navigation.
You need to use the correct navigation prop in your header, i.e. by
defining a callback for the options:
https://reactnavigation.org/docs/screen-options#options-prop-on-screen
You're using navigation prop passed from the parent navigator which is
a drawer, so the action is performed in the drawer.
Follow the git issue: https://github.com/react-navigation/react-navigation/issues/8806
To be more clear : we have to get the navigation prop from specific screen itself hence the screen stack will be notified of the history. using hook doesn't do this.

Set onpress on createDrawerNavigator item in react native?

I have a drawer item "Share App" where I want to open an alert and display a message rather than opening an entire screen in react native. My code is as follows:
const Screen6_StackNavigator = createStackNavigator({
//All the screen from the Screen6 will be indexed here
Sixth: {
screen: ShareApp, //don't want this screen
title:'Share',
navigationOptions: ({ navigation }) => ({
headerLeft: () => <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#138808',
},
headerTintColor: '#fff',
}),
},
});
const DrawerNavigatorExample = createDrawerNavigator({
ShareApp: {
//Title
screen: Screen6_StackNavigator,
navigationOptions: {
drawerLabel: 'Share App',
drawerIcon: (<Entypo name="share" size={20} color='black'></Entypo>)
},
},
);
Where Do I add the onPress parameter in order to call the function? I dont want the screen parameter, want a function to be called only when I click on Share App.
How to do that in react native??
Do help as I am new in React native development....
Thanks.
You can create a custom drawer content component and pass it to the contentComponent option in the DrawerNavigatorConfig.
Creating the custom drawer content:
const CustomDrawerContentComponent = (props) => (
<ScrollView>
<SafeAreaView
style={{ flex: 1 }}
forceInset={{ top: 'always', horizontal: 'never' }}>
<TouchableOpacity
onPress={() => {
// Do something...
Alert.alert('Heading', 'Body');
}}
style={{ left: 15, flexDirection: 'row', alignItems: 'center' }}>
<Entypo name="share" size={20} color='black'></Entypo>
<Text style={{ marginLeft: 30, fontWeight: 'bold' }}>Share App</Text>
</TouchableOpacity>
<DrawerItems {...props} />
</SafeAreaView>
</ScrollView>
);
The DrawerItems component will render clickable drawer options based on the screens you create, but above the DrawerItems we can add your share button for example.
Passing the custom drawer content component to contentComponent
const DrawerNavigatorExample = createDrawerNavigator(
{
Screen1: {
// Properties...
},
// Other screens...
},
{
// Pass custom drawer content component...
contentComponent: props => <CustomDrawerContentComponent {...props} />,
// Other configurations...
},
);
DrawerItems should be imported from react-navigation-drawer.

How to set always first screen of Stack Navigator inside Tab Navigator React Navigation 5

React Navigation 5
I've build a StackNavigator inside of a TabNavigator, and the navigation between home screen and other screens is working. But the problem is,When I move from Tab2 to Tab1 I expect Tab1 always show me first screen of StackNavigator.
tab1
-> Stack
-screen1
-screen2
tab2
I am on screen2 and then move to tab2
after that then I move back to Tab1 I want to always display screen1.
I am try to use
OnTabPress({navigation})=>{
navigation.navigate("stackName",{
screen: "screen1"
}).
}
Its work but its show me screen2 first then navigate to screen1. Is there any other Solution.
https://snack.expo.io/#usamasomy/groaning-donut
Use unmountOnBlur: true in options.
Eg.
<Tab.Screen
name="Stack1"
component={Stack1}
options={{
tabBarLabel: "Stack1",
unmountOnBlur: true,
}}
/>
So when you are navigating away from this tab and you're on screen2 of Stack1, you will always come on the first screen of this stackNavigator when coming back to this tab.
initialRouteName= "NAME" is the keyword to make sure you have a default
and make sure you use navigate() push() pop() accordingly.
Firstly, create a custom TabBar so we can write our own functions executed by onPress
function MyTabBar({ state, descriptors, navigation }) {
return (
<View style={{ flexDirection: 'row' }}>
{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 = () => {
navigation.reset({
index: 0,
routes: [{ name: 'Screen1' }],
})
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
}}
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
};
Then in the TabScreens override the original TabBar in Tab.Navigator by using tabBar=... then call navigation.reset() with index:0 and routes:{{name: 'Screen1'}} every time MyTabBar is pressed.
const TabScreens = ()=>{
return(
<Tab.Navigator tabBar={props => <MyTabBar {...props} />} initialRouteName="Tab1Screens" >
<Tab.Screen
name = "Tab1Screens"
component = {Tab1Screens}
/>
<Tab.Screen
name = "Tab2Screens"
component = {Tab2Screens}
/>
</Tab.Navigator>
)
}
return (
<TouchableOpacity
accessibilityRole="button"
accessibilityStates={isFocused ? ['selected'] : []}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID}
onPress={onPress}
onLongPress={onLongPress}
style={{ flex: 1 }}
>
<Text style={{ color: isFocused ? '#673ab7' : '#222' }}>
{label}
</Text>
</TouchableOpacity>
);
})}
</View>
);
}
This can be greatly improved eg:
-some logic before `navigation.reset()`
-Accessing onPress without creating a new component
-etc..
finally snack available here :https://snack.expo.io/#karammarrie/customtabbar
i have a simple solution is to set initialRouteName= "screen1" in
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
initialRouteName="screen1"
>
<Stack.Screen name="screen1" component={Screen1} />
<Stack.Screen name="screen2" component={Screen2} />
</Stack.Navigator>
{/** **/}
if the screen still shows the first screen 2, you just need to comment the line <Stack.Screen name="screen2" component={Screen2} /> and reload the screen, then remove the comment line.
There is no documentation about it, but the following code worked for me:
const navigationComp = useNavigation<StackNavigationProp<Screen1Stack>();
<Tab.Screen
name="Screen1 Tab"
component={Screen1StackScreen}
listeners={{
tabPress: () => {
navigationComp.replace('Screen 1 Child 1');
},
}}
/>
The code above always navigates to the 'Screen 1 Child 1' when the "Screen1 Tab" is pressed.
like this
e
xport default function BottonTab() {
const tabOffsetValue = useRef(new Animated.Value(0)).current;
return (
<View style={{flex: 1, backgroundColor: colors.primaryColor}}>
<Tab.Navigator
initialRouteName="Home"
screenOptions={{
showLabel: false,
tabBarShowLabel: false,
headerShown: false,
tabBarStyle: {
backgroundColor: colors.white,
position: 'absolute',
bottom: hp(0.51),
marginHorizontal: wp(2),
height: hp(8),
borderRadius: wp(2),
shadowColor: '#000',
shadowOpacity: 0.06,
shadowOffset: {
width: 10,
height: 10,
},
paddingHorizontal: 20,
},
}}>
<Tab.Screen
name={'Home'}
component={HomeScreen}
options={{
title: 'Home',
showLabel: false,
tabBarIcon: ({focused}) => (
<View>
<FontAwesome5
name="home"
size={wp(6)}
color={
focused ? colors.primaryColor : colors.secondaryTextColor
}
/>
</View>
),
}}
listeners={({navigation, route}) => ({
tabPress: e => {
Animated.spring(tabOffsetValue, {
toValue: getWidth() * 0,
useNativeDriver: true,
}).start();
},
})}
/>
<Tab.Screen
name={'HelpDiskScreen'}
component={HelpDiskScreen}
options={{
title: 'HelpDisk',
tabBarIcon: ({focused}) => (
<View>
<FontAwesome5
name="search"
size={wp(6)}
color={
focused ? colors.primaryColor : colors.secondaryTextColor
}
/>
</View>
),
}}
listeners={({navigation, route}) => ({
tabPress: e => {
Animated.spring(tabOffsetValue, {
toValue: getWidth() * 1.22,
useNativeDriver: true,
}).start();
},
})}
/>
<Tab.Screen
name={'ManageBookingScreen'}
component={ManageBookingScreen}
options={{
title: 'Manage',
tabBarIcon: ({focused}) => (
<View>
<Feather
name="settings"
size={wp(6)}
color={
focused ? colors.primaryColor : colors.secondaryTextColor
}
/>
</View>
),
}}
listeners={({navigation, route}) => ({
tabPress: e => {
Animated.spring(tabOffsetValue, {
toValue: getWidth() * 2.52,
useNativeDriver: true,
}).start();
},
})}
/>
<Tab.Screen
name={'ParkyingTypesScreen'}
component={ParkyingTypesScreen}
options={{
title: 'Parking',
tabBarIcon: ({focused}) => (
<View>
<FontAwesome5
name="bell"
size={wp(6)}
color={
focused ? colors.primaryColor : colors.secondaryTextColor
}
/>
</View>
),
}}
listeners={({navigation, route}) => ({
tabPress: e => {
Animated.spring(tabOffsetValue, {
toValue: getWidth() * 3.82,
useNativeDriver: true,
}).start();
},
})}
/>
</Tab.Navigator>
<Animated.View
style={{
width: getWidth(),
marginLeft: getWidth() * 0.58,
height: 2,
backgroundColor: colors.primaryColor,
bottom: hp(7),
borderRadius: 20,
transform: [{translateX: tabOffsetValue}],
}}></Animated.View>
</View>
);
}
Another option is to clear the stack of the navigation before navigating, so when you return to that screen, the navigation starts from the top
navigation.dispatch(StackActions.popToTop());
navigation.navigate("NextScreen");

How to change drawer header value from another component?

I'm new on react native. I'm using createDrawerNavigator for drawer list in this list i used a component to render a header with logged in user name. But i want to change that name from another component( profile screen). I'm unable to find solution.
Here is my drawer navigator code :
const AppDrawerNavigator = createDrawerNavigator({
Home: {
screen: Home,
navigationOptions: {
drawerLabel: 'Home',
drawerIcon: () => (
<Icon name="home" size={20} color="#0f1f7b" />
)
},
},
Profile: {
screen: Profile,
navigationOptions: {
drawerLabel: 'Profile',
drawerIcon: () => (
<Icon name="user" size={20} color="#0f1f7b" />
),
},
},
Logout: {
screen: Logout,
navigationOptions: {
drawerLabel: 'Logout',
drawerIcon: () => (
<Icon name="sign-out" size={20} color="#0f1f7b" />
)
},
}
},
{
drawerBackgroundColor: "#fff",
contentOptions: {
activeTintColor: '#000',
inactiveTintColor: '#000',
activeBackgroundColor: '#bfc7f3',
itemStyle: {
fontSize: 12,
},
},
contentComponent: (props) => (
<View>
<ScrollView>
<DrawerUserDetail />
<DrawerItems
{...props}
getLabel = {(scene) => (
<View style={{width:width/1.9}}>
<Text style={{color:'#000',fontSize:18,fontWeight:'500',paddingBottom:10,paddingTop:10}}>{props.getLabel(scene)}</Text>
</View>
)}
/>
</ScrollView>
</View>
)
});
Here is drawer user detail code :
constructor(props){
super()
this.state={
name:'',
}
}
render() {
return (
<View style={styles.profileBg}>
<Text style={{fontSize:20,color:'#fff',fontWeight:'600',left:20}}>Hello! {this.state.name}</Text>
</View>
);
}
I want change name state from profile component whenever user update name it will reflect on drawer screen.
You can create a separate component and use this component in your DrawerNavigator.
<DrawerUserDetail navigation={props.navigation} />
And here is component :
export default class DrawerUserDetail extends Component<Props> {
componentDidMount() {
//You can call your API here.
}
<View style={styles.profileBg}>
<View style={styles.profileHeader}>
<Text style={styles.name}>{this.state.name}{' '}</Text>
<Text onPress={()=> this.props.navigation.navigate('ProfileUpdate')}
style={styles.changePassword}>Manage Account</Text>
</View>
</View>
}

How to customize headerLeft React Navigation?

How can I customize headerLeft TabNavigator of React Navigation.
Here's one of my screens :
I want to remove the Back from the headerLeft
Is it possible ?
Here's my code :
DetailTabs = TabNavigator({
DetailResult:{
screen:DetailResult,
navigationOptions:{
title:'Detail Penginapan',
headerTitleStyle:{
fontSize:14,
textAlign: "center",
flex: 1,
},
tabBarVisible: false,
headerStyle:{
backgroundColor:'#4A94FB',
borderBottomColor: 'transparent',
},
headerTintColor: 'white'
}
}
})
By default, HeaderBackButton component is used. You can implement it and use it to override the back button styles, press props, for example:
link to docs
import { HeaderBackButton } from '#react-navigation/stack';
//in newer versions use:
//import {HeaderBackButton} from '#react-navigation/elements';
const styles = StyleSheet.create({
custom: {
// Custom styles here
}
});
<Screen
name="Home"
component={HomeScreen}
options={{
headerLeft: (props) => (
<HeaderBackButton
{...props}
style={styles.custom}
onPress={() => {
// Do something
}}
/>
),
}}
/>;
If you want full control, you can use your custom back button component, example:
import { CustomBackButton } from 'path/to/custom/component';
<Screen
name="Home"
component={HomeScreen}
options={{
headerLeft: (props) => (
<CustomBackButton {...props} />
),
}}
/>;
You probably just need to set headerBackTitle to null. Check out the docs for headerLeft for more info.
Like this:
DetailTabs = TabNavigator({
DetailResult:{
screen:DetailResult,
navigationOptions:{
title:'Detail Penginapan',
headerTitleStyle:{
fontSize:14,
textAlign: "center",
flex: 1,
},
tabBarVisible: false,
headerStyle:{
backgroundColor:'#4A94FB',
borderBottomColor: 'transparent',
},
headerTintColor: 'white',
headerBackTitle: null,
}
}
})
Key is to put this code from where the back button is clicked, not in App.js
In sample below, for Icon to work, use import Icon from 'react-native-vector-icons/Feather';
constructor(props) {
super(props);
this.state = {
// what ever
};
this.props.navigation.setOptions({
headerLeft: () => (
<TouchableOpacity
onPress={() => this.props.navigation.navigate('Home')}
>
<Icon style = {{paddingLeft : 10}} name="arrow-left" size={26} color="black" />
</TouchableOpacity>
),
});
}