How to include two buttons at headerLeft position? - react-native

I have been trying to include two icon buttons at headerLeft position but only one icon button appears at the position. I have mentioned my code below which has no errors. Using the code, I am unable to obtain the desired output that is only one of the two icon buttons is appearing at the headerLeft position. I have created AccountStack using createStackNavigator(). At the headerRight position hamburger icon appears to access the drawer. I want settings icon button and help icon button to appear at the headerLeft position together.
export default function AccountStack({navigation}) {
return (
<Stack.Navigator>
<Stack.Screen name="Account" component= {AccountScreen}
options={{headerRight: () => (<Ionicons.Button name="reorder-three" color={"#FF0000"} size={32} onPress={() => navigation.openDrawer()}/>),
headerLeft: ()=> ( <Ionicons.Button name= "settings" color={"#FF0000"} size={32}/> ,
<Ionicons.Button name= "md-help-circle" color={"#FF0000"} size={32}/> )}}/>
<Stack.Screen
name="Help"
component= {HelpScreen}
options={{headerRight: () => (<Ionicons.Button name="reorder-three" color={"#FF0000"} size={32} onPress={() => navigation.openDrawer()}/> ) }}/>
<Stack.Screen
name="Settings"
component= {SettingScreen}
options={{headerRight: () => (<Ionicons.Button name="reorder-three" color={"#FF0000"} size={32} onPress={() => navigation.openDrawer()}/> ) }}/>
</Stack.Navigator>
);
}
I am a beginner, kindly help me out in resolving the problem.

You can only render a single component in the headerLeft, therefore you need to wrap the two icons you want to set in a View
(Just for you to know: you can also build a more complex component to render in the headerLeft, with multiple buttons/texts etc)
<View>
<Ionicons.Button name= "settings" color={"#FF0000"} size={32}/> ,
<Ionicons.Button name= "md-help-circle" color={"#FF0000"} size={32}/>
</View>

Related

React Native - When I open a new screen, the bottom tab navigator is dismissed but screen page is not full height

Lets say I am in the tab - ChatStack and I am on the screen stack - AllChatRooms. Then when I click on one of the chat rows, I am then navigated to the chat room. I have it coded that, when in the ChatRoom screen, don't display nav bar and that works. But the ChatRoom screen does not reach full height and it acts like the nav bar is still there. I attached an image with colors so you can see what I am talking about.
Would really appreciate some help if anyone knows how to get the screen to reach the bottom of the phone screen.
So I am using a bottom tab navigator like this (simplified version):
Tabs.js
const getRouteName = (route) => {
const routeName = getFocusedRouteNameFromRoute(route);
if (routeName?.includes("HomeAllCategories") || routeName === "ChatRoom") {
return "none";
}
return "flex";
}
return (
<Tab.Navigator screenOptions={{ tabBarShowLabel: false }}>
<Tab.Screen name="Home" component={HomeStack}/>
<Tab.Screen name="Bookmarks" component={BookmarkStack}/>
<Tab.Screen name="Chats" component={ChatStack} options={({route}) => ({
tabBarStyle: {display: getRouteName(route)},
})}/>
<Tab.Screen name="Settings" component={SettingsStack}/>
</Tab.Navigator>
)
ChatStack.js
<Stack.Navigator>
<Stack.Screen name="AllChatRooms" component={AllChatRooms} />
<Stack.Screen name="ChatRoom" component={ChatRoom} />
</Stack.Navigator>
ChatRoom.js
return (
<SafeAreaView className="flex-1 bg-slate-900">
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
className="flex-1"
keyboardVerticalOffset={10}
>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<FlatList
data={messages}
className="pl-4"
keyExtractor={item => item.id}
renderItem={({ item }) =>
item.from === user.name ? (
<ReceiverMessage message={item} />
) : (
<SenderMessage message={item} />
)
}
/>
</TouchableWithoutFeedback>
{/* Text Box */}
<View className="bg-white flex-row justify-between items-center border border-gray-200 px-5 py-2">
<TextInput
className="h-10 text-lg w-4/5"
placeholder="Send Message..."
/>
<Button title="Send" color="#6ECCAF"/>
</View>
</KeyboardAvoidingView>
</SafeAreaView>
)
and I'm using:
"#react-navigation/bottom-tabs": "^6.5.2",
"#react-navigation/native": "^6.1.1",
"#react-navigation/native-stack": "^6.9.7",
But sometimes it does have the full height and I don't know why? On launch, the height of the screen is never working but after leaving and opening the chat room several times, the height of the screen does reach the bottom. Why is that?

How to minimize React Native Navigation Modal?

How to minimize a modal within a Stack Navigator in React Native so that the model still shows as a small bar at the bottom of the screen and stays even when switching tabs (like in the pictures I attached).
Picture of Modal opened
Picture of Modal miminized
Currently I have built a Bottom Navigation Tab Bar and within this Tab Navigator I have a Stack Navigator where the Modal can be opened.
<Tab.Navigator initialRouteName="Session">
<Tab.Screen name="Social">{() => <Social />}</Tab.Screen>
<Tab.Screen name="History">{() => <History />}</Tab.Screen>
<Tab.Screen name="Session" options={{headerShown: false}}>
{() => (
<Stack.Navigator>
<Stack.Screen name="Start Session">
{() => <StartSession navigate={navigate} />}
</Stack.Screen>
<Stack.Screen
name="New Template"
options={{
presentation: 'containedModal',
}}>
{() => <AddTemplate />}
</Stack.Screen>
</Stack.Navigator>
)}
</Tab.Screen>
<Tab.Screen name="Activities">{() => <Activities />}</Tab.Screen>
<Tab.Screen name="Profile">
{() => <Profile setUser={setUser} setUserCreds={setUserCreds} />}
</Tab.Screen>
</Tab.Navigator>
You can achieve this using a bottom sheet instead of using a modal from react native navigation.
Something like:
https://www.npmjs.com/package/#gorhom/bottom-sheet

How can I hide the screen header but show my back button?

I would like to hide my screen header but still show the back button in my Stack Navigator? I have set screenOptions={{ headerShown: false }} in my Stack.Navigator, which hides both the screen header and back button. I would like to just hide the screen header.
Can someone please assist with this? Below is my Stack Navigator:
function SearchStack() {
return (
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="SearchScreen" component={SearchScreen} />
<Stack.Screen name="SearchListScreen" component={SearchListScreen} />
</Stack.Navigator>
);
}
In the tab navigator the stack is set as:
<Tab.Navigator screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {...})}>
<Tab.Screen name="Search" component={SearchStack} />
</Tab.Navigator>
This is what I'm currently seeing:
But this is what I would like to have with my Tab navigation bar still at the bottom for the search stack:
This is what I get using options={{headerMode:"none"}} in Stack.Navigator:
The below occurs when adding updating the Stack.Navigator to <Stack.Navigator screenOptions={{ headerTitle:"", headerTransparent:true }}> . How can add or move the back button to the top exactly like the 2nd image, which is achieved when not adding the Stack to the Tab.Screen so changing:
<Tab.Screen name="Search" component={SearchStack} />
to
<Tab.Screen name="Search" component={SearchScreen} />
but doing this causes the tab to not appear in the Search list screen.
The back button is part of the header, so you can't hide the header and keep the back button.
What you want to do is to hide other parts of the header except for the back button, which would be
Title, with headerTitle: ""
Background, with headerTransparent: true
for hide the back button in react-native, we can use property,
headerBackVisible:false this property only work on android
<Stack.Screen
options={{headerBackVisible: false}}
/>
example use of in Stack
const CustomerStack = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="First"
component={First}
options={{headerShown: false}}
/>
<Stack.Screen
name="Third"
component={Third}
options={{headerTitle: '', headerTransparent: true}}
/>
</Stack.Navigator>
);
}
If you don't want the default header then use like this
screenOptions={{ headerShown: false }}
and write custom code for the header with back button in your component
(If your are using class component) Then
<TouchableOpacity onPress={()=>this.props.navigation.goBack()} style={{width:'100%', height:45, flexDirection:'row'}}> <Image source={require('back button image path')}/> </TouchableOpacity>
if you want header title too then,
<TouchableOpacity onPress={()=>this.props.navigation.goBack()} style={{width:'100%', height:45, flexDirection:'row'}}> <Image source={require('back button image path')}/> <Text>SearchListScren</Text> </TouchableOpacity>
Put this code at top of the component code under a container

Adding a back button for each bottom tab with React Navigation

The bottom tabs navigation is looking something like that:
const Tab = createBottomTabNavigator();
export default function TabStackScreen() {
return (
<Tab.Navigator initialRouteName="Home">
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Favorites" component={FavoritesStackScreen} />
<Tab.Screen name="Search" component={SearchStackScreen} />
</Tab.Navigator>
)
}
There is not back button on the favorites and search screen. I guess this is the normal behavior, but I would love to have one.
I did not find something relevant in the doc, except recreating a component that looks like the native back button and adding it on some screens using headerLeft. Is there a more simple method?
In my projects I like to create custom headers, and I do not show the default header and show my own custom header component.
On my custom component I add right and left components, and let the screens decide what to do, by default the back button is shown, but if the screen pass the noBack property, the button is hidden.
You can also add a right component, for example a close button.
That is what I use to do:
const screenOptions = {
headerShown: false
};
<RootStack.Navigator screenOptions={screenOptions} mode="modal">
and then create my own component
export const Header = ({ title, leftComponent, rightComponent, noBack }) => {
const navigation = useNavigation();
return (
<Wrapper>
{leftComponent ||
(noBack ? (
<Placeholder />
) : (
<Button
onPress={() => navigation.goBack()}
accessible
accessibilityRole="button"
accessibilityLabel="Back">
<Icon
size={30}
name={Platform.OS === 'android' ? 'arrow-left' : 'chevron-left'}
/>
</Button>
))}
<Title bold accessibilityRole="header" acessible acessibilityText={title}>
{title}
</Title>
{rightComponent || <Placeholder />}
</Wrapper>
);
};
Doing that, you are able to customize everything on your header, it works like a charm for me.

React native navigation 5 passing updated component

I am new to react native and its navigation modules. I have a simple dashboard.js file where I am using tab navigator like this -
<Tabs.Navigator tabBarOptions={{ activeTintColor: '#ff5757' }}>
<Tabs.Screen
options={{
tabBarIcon: ({ color }) =>
<Icon name='star-border' size={30} padding={15} color={color} />,}}
name={'Orders'}
component={Order}
initialParams={{user}}
/>
<Tabs.Screen
component= {AnotherComponent}
/>
As you can see I am passing InitialParams where I have user props. And I can easily get it in Order component by route.params.
However, in my dashboard component I also have a method that runs every 1 minute and updates user props.
I can't get the updated value of user props in Order component. I am stuck with this for 2 days. In the past I have done like this -
<Tabs.Screen
component = {() => <SomeComponent props= {props}/>}
And it worked fine. But with react-navigation 5 its not working any more.
Please help me if anyone knows. plz.
Thanks a lot.
The initial props seems to be a constant also as per the documentation you have to use redux or context api to update the badge counts in the tabs so I think it will be better to take that approach to handle this problem. Came up with a count changing scenario just like yours using context API.
const CountContext = React.createContext(0);
function HomeScreen() {
return (
<View>
<CountContext.Consumer>
{value => <Text>Home! {value}</Text>}
</CountContext.Consumer>
</View>
);
}
const MyTabs = () => {
const [count, setCount] = React.useState(0);
return (
<CountContext.Provider value={count}>
<View style={{ flex: 1 }}>
<Text>{count}</Text>
<Button title="count" onPress={() => setCount(count + 1)} />
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} options={{ title: 'My home' }} />
<Tab.Screen name="Settings" component={SettingsScreen} options={{ title: 'My home 2' }} />
</Tab.Navigator>
</View>
</CountContext.Provider>
);
};
This way you can skip the navigation params and directly send data to the tab, and this data can be read from other tabs or somewhere down the tree as well.
You can check the full snack here
https://snack.expo.io/#guruparan/5c2b97