I am using #react-navigation/material-top-tabs to display tabs in my application. How can I inject NativeID to tabs to have an access to them with e.g. Selenium?
The only way that I found was using tabBar property, creating custom tabs and adding NativeID to TouchableOpacity. Is there more simple way?
<NavigationContainer>
<Tab.Navigator tabBar={(props) => <MyTabBar {...props} />} >
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
</NavigationContainer>
function MyTabBar({ state, descriptors, navigation, position }) {
return (
<View style={{ flexDirection: 'row', paddingTop: 20 }}>
{
state.routes.map((route, index) => {
// ....
return (
<TouchableOpacity nativeID={"tab_"+label} >
<Animated.Text style={{ opacity }}>{label}</Animated.Text>
</TouchableOpacity>
);
})}
</View>
);
}
Related
I make drawer.navigator that nested tab.navigator, Then show an icon that I didn't add to the code! and tried to remove it but couldn't...!! Does anybody have an idea?
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Home">
{()=>
<Tab.Navigator screenOptions={{
***// I try this but didn't work.***
// tabBarIcon: ()=>{return null}
tabBarIcon: ({focused,color,size})=>
{
***// I do what in here???***
},
tabBarIconStyle:{
// I try this too but didn't work.
display: 'none',
},
tabBarStyle: {
borderTopColor: 'rgba(0, 0, 0, .2)',
},
tabBarLabelStyle: {
fontSize: 13,
// I use one of this then run code! one time I use two of this! but didn't
worked!!
textAlignVertical: 'center',
justifyContent: 'center',
},
tabBarLabelPosition: 'beside-icon'
}}
>
<Tab.Screen name="Todos"
options={{
headerShown: false,
}}>
{ ()=>
<Home
todos={todos}
pressHandler={pressHandler}
submitHandler={submitHandler}
/>}
</Tab.Screen>
<Tab.Screen name='CompleteTodos' options={{headerShown: false}}>
{()=>
<CompleteTodos
todos={todos}
pressHandler={pressHandler}
/>}
</Tab.Screen>
</Tab.Navigator>
}
</Drawer.Screen>
<Drawer.Screen name="About" component={About} />
<Drawer.Screen name="Settings" component={Settings} />
</Drawer.Navigator>
</NavigationContainer>
with no options
with display: none. BUT THE LABEL DIDN't CENTERED!!
You can completely replace the tab component for a custom made by you.
As noted in the React Navigation docs:
tabBarButton: props => <TouchableOpacity {...props} />
You can find further information on how to fully customized your navigation here: https://reactnavigation.org/docs/bottom-tab-navigator
I want to add a button(icon) on stack header(on right side). On-click it goes to that page but it's not working. It appears 'undefined is not an object (evaluating 'navigation.navigate')'.
Below is my code:
<Stack.Navigator>
<Stack.Screen name="Page1" component={Page1} />
<Stack.Screen
name="Page2"
component={Page2}
options={{
headerRight: () => (
<View>
<TouchableOpacity
onPress={() => navigation.navigate('Page3')}>
<Image source={require('../assets/image.png')} />
</TouchableOpacity>
</View>
)
}}
/>
<Stack.Screen name="Page4" component={Page4} />
<Stack.Screen name="Page5" component={Page5} />
</Stack.Navigator>
You can pass the navigation from the options to the headerRight:
options={({navigation}) => ({
headerRight: () => (
...
),
})}
or useNavigation():
const navigation = useNavigation();
EDIT 2:
fixed your snack code and its working fine:
You had to add a stackScreen called 'MyorderStack' because you're trying to navigate to that.
<NavigationContainer independent={true}>
<Stack.Navigator screenOptions={{ headerTintColor: 'blue' }}>
<Stack.Screen name="Global Page" component={AppNavigator} options={{ headerShown: false }} />
<Stack.Screen name="DetailOne" component={DetailOne} options={({navigation}) => ({ headerBackTitleVisible: false, title: 'Global Page',
headerRight: () => (
<View style={{flexDirection: 'row',justifyContent: 'flex-end',width: '50%'}}>
<View style={{ marginRight: 10 }}>
<TouchableOpacity onPress={() => navigation.navigate('MyorderStack')}>
<Image source={require('./assets/shop.png')} style={styles.Image} />
</TouchableOpacity>
</View>
</View>
), headerTitleAlign:'center', headerTintColor:colors.primary
})}
/>
<Stack.Screen name="DetailTwo" component={DetailTwo} options={{headerBackTitleVisible: false, headerTitleAlign: 'center', title: 'Global Page', headerTintColor: colors.primary}} />
<Stack.Screen name="MyorderStack" component={MyorderStack} options={{headerBackTitleVisible: false, headerTitleAlign: 'center', title: 'Global Page', headerTintColor: colors.primary}} />
</Stack.Navigator>
</NavigationContainer>
Navigation is only defined within the screen's components. In your case, you can try useNavigation hook to navigate to different screen. Import it like:
import { useNavigation } from '#react-navigation/native';
and declare it like:
const navigation = useNavigation();
Then you it to your TouchableOpacity prop like onPress={() => navigation.navigate('Page3')}.
Hope this works for you. Thanks
I've got 3 screens in a Drawer Navigation and 1 screen in a stack Navigation.
app.js
const Stack = createStackNavigator();
function Navigator() {
return (
<Stack.Navigator>
<Stack.Screen name="Spelare" component={PlayersScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
);
}
const Drawer = createDrawerNavigator();
export default function App() {
return (
<NavigationContainer>
<Drawer.Navigator
initialRouteName="Hem"
drawerPosition="right"
drawerType="slide">
<Drawer.Screen
name="Hem"
component={HomeScreen}
style={styles.drawerItem}
/>
<Drawer.Screen
name="Kontakt"
style={{ color: 'red' }}
component={ContactScreen}
/>
<Drawer.Screen
name="Spelare"
style={{ color: 'red' }}
component={PlayersScreen}
/>
</Drawer.Navigator>
</NavigationContainer>
);
};
function StackNavigator() {
return (
<NavigationContainer>
<Drawer.Navigator
initialRouteName="Hem"
drawerPosition="right"
drawerType="slide">
<Drawer.Screen
name="Hem"
component={HomeScreen}
style={styles.drawerItem}
/>
<Drawer.Screen
name="Kontakt"
style={{ color: 'red' }}
component={ContactScreen}
/>
{/* Look down ... */}
<Drawer.Screen
name="Details"
style={{ color: 'red' }}
component={DetailsScreen}
/>
</Drawer.Navigator>
</NavigationContainer>
);
}
On the PlayersScreen i've got a FlatList rendering names and when clicking on a name i want it to take the user to Details Screen and load only that person. This all worked when having the DetailsScreen in the Drawer navigator but i don't want that showing in the Drawer menu in the App.
FlatList, Inside playerScreen which is also in the App.js file
<FlatList
data={data}
keyExtractor={item => item.Name}
renderItem={({ item }) => (
<View style={{alignItems: 'center', backgroundColor: '#25D495', borderRadius: 15, fontFamily: 'Roboto, sans-serif', marginBottom: 15, height: 40}}>
<Text
style={styles.listStyle} onPress={() => {navigation.navigate('Details', {itemId: item._id})}}>{item.Name}
</Text>
</View>
)}
/>
I get the following ERROR : The action 'NAVIGATE' was not handled by any Navigator, do you have a screen named Details?
Any help is appreciated.
I'd suggest you replace Spelare screen in your drawer with a StackNavigator like so..
First
Create a stack having both PlayersScreen, and DetailsScreen
const Stack = createStackNavigator();
function StackNavigator() {
return (
<Stack.Navigator>
<Stack.Screen name="Spelare" component={PlayersScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
);
}
Second
Replace your PlayersScreen in your Main drawer navigator with your created Stack
return (
<NavigationContainer>
<Drawer.Navigator
initialRouteName="Hem"
drawerPosition="right"
drawerType="slide">
<Drawer.Screen
name="Hem"
component={HomeScreen}
style={styles.drawerItem}
/>
<Drawer.Screen
name="Kontakt"
style={{ color: 'red' }}
component={ContactScreen}
/>
{/* Look down ... */}
<Drawer.Screen
name="SpelareStack"
style={{ color: 'red' }}
component={Stack}
/>
</Drawer.Navigator>
</NavigationContainer>
);
in my app home screen I want to custom the header to have two icons in left and right which can be done using:
<HomeStack.Screen
name="Home"
component={HomeScreen}
options={{
title: '',
headerLeft: () => (
<View style={{ marginLeft: 10 }}>
<Icon.Button
name="ios-menu"
size={25}
color="#000000"
backgroundColor={COLORS.primary}
onPress={() => navigation.openDrawer()}
/>
</View>
),
headerRight: () => (
<View style={{ marginLeft: 10 }}>
<Icon.Button
name="location-outline"
size={25}
color="#000000"
backgroundColor={COLORS.primary}
onPress={() => navigation.openMap()}
/>
</View>
),
}} />
</HomeStack.Navigator>
I want to add additional but to be in the center which will be customized based on my needs, but I have no idea how to implement that as there is nothing called headerCneter:
Perhaps you can take advantage of the header option inside the stack navigator? You can then use the route params to customize your header from there.
You can pass react component in headerTitle:
<HomeStack.Screen
name="Home"
component={HomeScreen}
options={{
headerTitle: () => {
return (
<View style={st.horizontalRow}>
<LeftIcon />
<TextInput
placeholder="search"
/>
<RightIcon />
</View>
);
},
headerTitleAlign: 'left',
headerTitleContainerStyle: {
left: 40,
right: 0,
},
}} />
BottomTabNavigator doesn't show when code like this:
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
function Bottom() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Setting" component={SettingsScreen} />
</Tab.Navigator>
);
}
function AppRoot() {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="HomePage"
screenOptions={{ gestureEnabled: false }}>
//this is bottom tab navigator, it doesn't show.
<Stack.Screen name="Bottom" component={Bottom} />
<Stack.Screen
name="HomePage"
component={HomePage}
/>
<Stack.Screen
name="Page1"
component={Page1}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
AppRegistry.registerComponent(appName, () => AppRoot);
But when I don't use nesting Stack,BottomTabNavigator works fine.
Like this:
function AppRoot() {
return (
<NavigationContainer>
<Bottom />
</NavigationContainer>
);
}
How to use both in one page, normal navigator and bottom tab navigator.
As per your code 'HomePage' is the initial screen and the bottom tab is added on screen named 'Bottom'. Use DrawerNavigator to add sidemenu and you can add bottom tab on one of the screen as show below:
const Drawer = createDrawerNavigator();
const Tab = createBottomTabNavigator();
function HomeScreen({navigation}) {
return (
<View style={{flex: 1}}>
<View style={{alignSelf:'flex-start'}}>
<Button
onPress={() => navigation.toggleDrawer() }
title="Menu"
/>
</View>
<View style={{alignSelf:'center',justifyContent:'space-around'}}>
<Button
onPress={() => navigation.navigate('Notifications')}
title="Go to notifications"
/>
</View>
</View>
);
}
function Tab1() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Tab1!</Text>
</View>
);
}
function Tab2() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Tab2!</Text>
</View>
);
}
function NotificationsScreen({navigation}) {
return (
<Tab.Navigator>
<Tab.Screen name="Tab1" component={Tab1} />
<Tab.Screen name="Tab2" component={Tab2} />
</Tab.Navigator>
);
}
function SettingsScreen({navigation}) {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Button
onPress={() => navigation.navigate('Home')}
title="Go back home"
/>
</View>
);
}
export default function App() {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home" drawerPosition="left"
drawerType="slide">
<Drawer.Screen
name="Home"
component={HomeScreen}/>
<Drawer.Screen name="Notifications" component={NotificationsScreen} />
<Drawer.Screen name="Settings" component={SettingsScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
}