headerRight button misaligned - react-native

I am having trouble aligning the headerRight consistently across Screens.
I have a StackNavigator with a nested TabNavigator:
const Tabs = ({navigation}) => {
return (
<Tab.Navigator
screenOptions={{
headerRight: () => (
<View style={{backgroundColor: 'red'}}>
<IconButton icon="account" onPress={navigation.navigate('Profile')}/>
</View>
),
}}>
<Tab.Screen name="Home" component={Screens.Home}/>
<Tab.Screen ... />
</Tab.Navigator>
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
{!auth.user ? (
<Stack.Screen name="Login" component={Screens.Login} />
) : (
<>
<Stack.Screen name="Tabs" component={Tabs} />
<Stack.Screen
name="Profile"
component={Screens.Profile}
options={({navigation}) => ({
headerShown: true,
headerRight: () => (
<View style={{backgroundColor: 'red'}}>
<IconButton icon="close" onPress={navigation.goBack()}/>
</View>
),
})}
/>
</>
)}
</Stack.Navigator>
</NavigationContainer>
Here are 2 screenshots showing the header buttons, the first is the <Stack.Screen name="Profile"> and the second is the <Tab.Screen name="Home">:
As you navigate between the 2 screens the top right button jumps right to left because of the spacing to the right of the button on the Profile Screen.
I have tried moving items around (screens, nesting, options vs screenOptions...), and tried other options and screenOptions but have not had any luck.
It seems like a StackScreen has padding whereas the TabScreen does not.
Any ideas here?

Related

Turning off the drawer header in a specific screen in bottom tab navigation in drawer navigation in react native

I have a very big problem I am using two navigations in one app the first one is the drawer navigator this is how I use the drawer navigator:
<Drawer.Navigator
screenOptions={{
drawerStyle: {
backgroundColor: 'white',
},
}}
drawerContent={props => <CustomSidebarMenu {...props} />}
drawerContentOptions={{
activeTintColor: '#e91e63',
activeBackgroundColor: 'red',
itemStyle: {marginVertical: 20},
}}>
<Drawer.Screen
options={{
headerShown: true,
headerTitle: () => (
<Image
style={{height: 150, width: 100, resizeMode: 'contain'}}
source={require('../assets/images/referans2.png')}
/>
), // Title to appear in the header
headerRight: ({navigation, scene}) => (
// Custom component to appear on the right side of the header
<View style={{flexDirection: 'row'}}>
<Pressable>
<Ionicons
name="notifications-outline"
size={30}
color={'black'}
/>
</Pressable>
<Pressable style={{marginHorizontal: 10}}>
<Ionicons
name="chatbubbles-outline"
size={30}
color={'black'}
/>
</Pressable>
</View>
),
}}
name="Ana Sayfa"
component={Main}
/>
<Drawer.Screen
options={{headerShown: true}}
name="Şiparişlerim"
component={MyOrders}
/>
<Drawer.Screen name="Adreslerim" component={AddressesScreen} />
<Drawer.Screen name="Üyelik Bilgilerim" component={AccountInfoScreen} />
</Drawer.Navigator>
[
and this gives me the following output:](https://i.stack.imgur.com/73o8f.png)
In the main function you see here, the bottomtabnavigator, which I use in the whole app, returns.:
const Main = () => {
return (
<Tab.Navigator screenOptions={screenOptions}>
<Tab.Screen
component={HomeStack}
name="Ana Sayfa"
options={{
tabBarIcon: ({focused, color}) => (
<Ionicons name="home-outline" size={28} color={color} />
),
}}
/>
<Tab.Screen
component={CategoriesStack}
name="Kategoriler"
options={{
tabBarIcon: ({focused, color}) => (
<Ionicons name="grid-outline" size={28} color={color} />
),
}}
/>
<Tab.Screen
component={CartStack}
name="Sepet"
options={{
tabBarIcon: ({focused, color}) => (
<Ionicons name="cart-outline" size={28} color={color} />
),
}}
/>
<Tab.Screen
component={DiscoverStack}
name="Keşfet"
options={{
tabBarIcon: ({focused, color}) => (
<Ionicons name="compass-outline" size={28} color={color} />
),
}}
/>
<Tab.Screen
component={ProfileStack}
name="Profilim"
options={{
headerShown: true,
tabBarIcon: ({focused, color}) => (
<Ionicons name="person-circle-outline" size={28} color={color} />
),
}}
/>
</Tab.Navigator>
);
};
What I want is this; Turning off the header of the drawer in the profile stack in the bottom tab navigator, but I can't do it
but it still didn't close the header of the drawer navigation. Even if I set the headershown of the drawer to false, the header on all screens closes, I'm just not on the screen I want
As far as I understand, there are 3 nested navigator.
Drawer
|---------> BottomTab
| |---------> ProfileStack
|... |...
If you want to hide or show only specific screen you can use navigation.setOptions()
For example,we have a Profile screen in ProfileStack and get navigation with screen props or useNavigation()
If you want to hide ProfileStack header in Profile:
React.useLayoutEffect(() => {
navigation.setOptions({ headerShown:false })
})
If you want to hide BottomTab header in Profile:
React.useLayoutEffect(() => {
navigation.getParent().setOptions({ headerShown:false })
})
If you want to hide Drawer header in Profile:
React.useLayoutEffect(() => {
navigation.getParent().getParent().setOptions({ headerShown:false })
})
You can use setOptions with headerShown:true when the drawer screenOptions headerShown:false
react-navigation getParent() and setOptions() docs

What's the correct approach for having a list/detail view with React Native Navigation Bottom Tab?

I have something like:
const Tab = createBottomTabNavigator<DefaultTabbedParamList>();
const DefaultTabbedNavigation = () => {
return (
<>
<Tab.Navigator initialRouteName='Home' screenOptions={{
unmountOnBlur: true,
}}>
<Tab.Screen name="Home" component={HomeScreen} options={{
...defaultOptions,
tabBarIcon: ({ color, size, focused }) => (
<Icon as={Ionicons} name={`home${focused ? `` : `-outline`}`} size={size} color={color} />
)
}} />
...
</Tab.Navigator>
</>
);
}
When a user clicks to a detail view from Home (or any other tab), I want to load a detail view with the currently selected tab remaining.
What's the correct approach to handle this?
One idea I had was to have a StackNavigator in HomeScreen that includes a Detail screen. But it seems repetitive to do for every screen, no?
You can do something like this :-
<Tab.Navigator initialRouteName='Home' screenOptions={{
unmountOnBlur: true,
}}>
<Tab.Screen name="Home" component={HomeScreen} options={{
...defaultOptions,
tabBarIcon: ({ color, size, focused }) => (
<Icon as={Ionicons} name={`home${focused ? `` : `-outline`}`} size={size} color={color} />
)
}} />
// Something like this.
<Tab.Screen name="Home2" children={({route}) => <route?.name />} ...{otherProperties}/>
...
</Tab.Navigator>
Note:- To use this kind of approch your routeName and componentName should be same.
How about this?
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name={"Tabs"} component={Tabs} />
<Stack.Screen name={"Detail"} component={DetailScreen} />
</Stack.Navigator>
</NavigationContainer>
);
Yeah, you'll likely want to define a StackNavigator for each tab. It's a bit repetitive, but that's been a theme of my experience with RN.
You can do something like:
const HomeStackNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Detail" component={DetailScreen} />
</Stack.Navigator>
);
};
const OtherStackNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Other" component={OtherScreen} />
<Stack.Screen name="Detail" component={DetailScreen} />
</Stack.Navigator>
);
};
const DefaultTabbedNavigation = () => {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeStackNavigator} />
<Tab.Screen name="Other" component={OtherStackNavigator} />
</Tab.Navigator>
)
}

How to I hide screens using DrawerNavigator in React Native

I have created a Drawer Navigator with some screens that I want the user to be able to see and access, however, I also want to be able to navigate to a screen in which the user can only access if they press a button to go to. So that screen should not be accessible through the drawer screen. The problem is that I have no idea how to do that. I have searched everywhere and still didn't fidn a way to do it.
AppStack.js:
const Drawer = createDrawerNavigator();
const AppStack = () => {
return (
<Drawer.Navigator
drawerContent={props => <CustomDrawer {...props}/>}
screenOptions={{headerShown: false,drawerActiveBackgroundColor: '#000c1a', drawerActiveTintColor: 'white', drawerInactiveTintColor: 'white', drawerLabelStyle: {marginLeft: -25, fontSize: 17}}}
>
<Drawer.Screen name="Home" component={HomeScreen} options={{
drawerIcon: ({color}) => (
<Ionicons name="home-outline" size={24} color={color} />
)
}}/>
<Drawer.Screen name="Inventory" component={ListingScreen} options={{
drawerIcon: ({color}) => (
<Ionicons name="car-sport-outline" size={24} color={color} />
)
}}/>
<Drawer.Screen name="Iventory" component={ListingScreen} options={{
drawerIcon: ({color}) => (
<Ionicons name="car-sport-outline" size={24} color={color} />
)
}}/>
<Drawer.Screen name="Inventy" component={ListingScreen} options={{
drawerIcon: ({color}) => (
<Ionicons name="car-sport-outline" size={24} color={color} />
)
}}/>
<Drawer.Screen name="Invent" component={ListingScreen} options={{
drawerIcon: ({color}) => (
<Ionicons name="car-sport-outline" size={24} color={color} />
)
}}/>
</Drawer.Navigator>
)
}
export default AppStack
App.js
export default function App() {
const Stack = createNativeStackNavigator()
return (
<View style={styles.container}>
<NavigationContainer theme={MyTheme}>
<AppStack/>
</NavigationContainer>
</View>
);
}
Is there any way I could do this?
To make it easier to understand, I have a list of cars that whenever a user press on the picture of the car, it will go to a vehicle details screen with the info of the car the user clicked.
I'd really appreciate any help.

Component not rendering in headerTitle

My HomeHeader component is not rendering within the headerTitle. I am expecting to render since when I do it as a direct string it shows up in the headerTitle.
const HomeHeader = (props) => {
return (
<View>
<Text>Home</Text>
</View>
)
}
function RootNavigator() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} options={{headerTitle: HomeHeader}} />
<Stack.Screen name="ChatRoom" component={ChatRoomScreen} options={{ headerShown: true }} />
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
<Stack.Group screenOptions={{ presentation: 'modal' }}>
<Stack.Screen name="Modal" component={ModalScreen} />
</Stack.Group>
</Stack.Navigator>
);
}
Is there something I am missing? Please see the HomeHeader component up top and then it is currently within the headerTitle of my home screen.
I would add some size to the View and some style to the text maybe ...

Always show BottomTabNavigation

How can I show BottomTabNavigation even on stacked screen? I have tried this for a few hours but really don't get it to work as expected.
So the thing I want to happen is, if I navigate to say for example the Title Screen, I still want to show the BottomTabNavigation. Any suggestions?
I can of course create a new navigation, but then it is sliding in from the side.
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
const HomeTabNavigator = () => {
return (
<Tab.Navigator
tabBarOptions={{
labelStyle: {textTransform: 'uppercase'},
style: {
backgroundColor: '#111111', //Färger på footerbar
borderTopColor: 'transparent',
borderBottomColor: 'transparent',
},
}}>
<Tab.Screen
name={'Concerts'}
component={ConcertsScreen}
options={{
tabBarIcon: ({tintColor}) => (
<Image
source={require('../../assets/icons/concerts.png')}
size={25}
/>
),
}}
/>
<Tab.Screen
name={'Docs'}
component={DocumentiesScreen}
options={{
tabBarIcon: ({tintColor}) => (
<Image source={require('../../assets/icons/docs.png')} size={25} />
),
}}
/>
<Tab.Screen
name={'Profile'}
component={ProfileScreen}
options={{
tabBarIcon: ({tintColor}) => (
<Image source={require('../../assets/icons/user.png')} size={25} />
),
}}
/>
</Tab.Navigator>
);
};
const Router = () => {
const {token, setToken} = useContext(TokenContext);
const {userFav, addFav, getFav} = useContext(UserContext);
const [isLoading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
setTimeout(() => {}, 1000);
}, []);
return (
<NavigationContainer>
{token ? (
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
headerTransparent: true,
noBorder: true,
}}
headerMode="float">
<Stack.Screen name={' '} component={HomeTabNavigator} />
<Stack.Screen name={'Concerts'} component={ConcertsScreen} />
<Stack.Screen name={'User Profile'} component={ProfileScreen} />
<Stack.Screen
name={'FavouritesScreen'}
component={FavouritesScreen}
/>
<Stack.Screen name={'Docs'} component={DocumentiesScreen} />
<Stack.Screen name={'AccountScreen'} component={AccountScreen} />
<Stack.Screen name={'Home of'} component={SearchScreen} />
<Stack.Screen name={'Artist'} component={ArtistScreen} />
<Stack.Screen name={'Title'} component={Videos} />
<Stack.Screen name={'PlayVideo'} component={PlayVideo} />
</Stack.Navigator>
) : (
<LoginScreen />
)}
</NavigationContainer>
);
};
You need to nest all your stack screens inside a tab screen.
The BottomTabNavigator disappear because you leave your Tab.Navigator component.
I hope this helps. If you want to navigate between screens that are related to a specific tab button, and have that tab button remain active while moving between these screens, you should set up a StackNavigation within that tab's component. By doing so, the tab button will remain active while navigating within its related screens.
On the other hand, if you want the TabNavigation to be visible throughout the whole application but some screens should not be displayed as tabs, you can add all screens inside the TabNavigation and specify in the options for those screens not to be displayed as tab buttons. That way, while in the screen without a tab button, the tabs will still be visible but none will be active. For example, you can do this for a screen called 'Title':
<Tab.Screen
name={'Title'}
component={Videos}
options={{
tabBarIcon: ({tintColor}) => (
<Image source={require('../../assets/icons/user.png')} size={25} />
),
tabBarButton: () => null <---- *this causes it to have no button*
}}
/>
I hope this helps!