How to add a buttont that handle display of DrawerNav to TabNav - react-native

How to implement a buttom navigator that containt a button that handle DrawerNav display

To be able to do it, first you would have to add your custom tab bar, by overriding the tabBar property on the Tab.Navigator component. Here is an example from the official React Navigation docs.
Then you would have to add a button to your custom tab bar, which purpose would be to open the drawer screen (navigation.openDrawer).
Here's an example how you could do it:
import React from 'react';
import {
Button,
SafeAreaView,
Text,
TouchableOpacity,
View,
} from 'react-native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { createDrawerNavigator } from '#react-navigation/drawer';
const Tab = createBottomTabNavigator();
const TabItem = ({ label, onPress, isFocused = false }) => (
<TouchableOpacity
accessibilityRole="button"
onPress={onPress}
style={{
flex: 1,
padding: 20,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text style={{ color: isFocused ? '#673ab7' : '#222' }}>{label}</Text>
</TouchableOpacity>
);
const MyTabBar = ({ state, descriptors, navigation }) => {
const focusedOptions = descriptors[state.routes[state.index].key].options;
if (focusedOptions.tabBarVisible === false) {
return null;
}
const onOpenDrawerPress = () => {
navigation.openDrawer();
};
return (
<View style={{ flexDirection: 'row' }}>
<TabItem label="Open drawer" onPress={onOpenDrawerPress} />
{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 = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
return (
<TabItem label={label} onPress={onPress} isFocused={isFocused} />
);
})}
</View>
);
};
const TabOneScreen = () => (
<SafeAreaView>
<Text>Tab One screen</Text>
</SafeAreaView>
);
const TabTwoScreen = () => (
<SafeAreaView>
<Text>Tab Two screen</Text>
</SafeAreaView>
);
const TabNavigator = () => {
return (
<Tab.Navigator tabBar={MyTabBar}>
<Tab.Screen name="TabOneScreen" component={TabOneScreen} />
<Tab.Screen name="TabTwoScreen" component={TabTwoScreen} />
</Tab.Navigator>
);
};
const Drawer = createDrawerNavigator();
const Notifications = ({ navigation }) => (
<SafeAreaView>
<Text>Notifications Screen</Text>
<Button title="Open drawer" onPress={navigation.openDrawer} />
</SafeAreaView>
);
const Router = () => {
return (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={TabNavigator} />
<Drawer.Screen name="Notifications" component={Notifications} />
</Drawer.Navigator>
);
};
export default Router;
Maybe the only "drawback" would be that you have to customize the custom tab bar so that you can achieve your desired look and feel. However, that could also prove to be better in the long run, as you have more control over your tab bar and its items.

Related

Flatlist item redirects to details page

I am new at react native and I am trying to make a detail page for my crypto price API.
What I need to do is when the user press on crypto he is redirected to a detail screen page where he can see charts, price etc. I have no idea what I should do next, I tried onpress() but it did not work. How can I make those flatList elements that are displayed using CryptoList when clicking on them shows detail page?
App.js
export default function App() {
const [data, setData] = useState([]);
const [selectedCoinData, setSelectedCoinData] = useState(null);
useEffect(() => {
const fetchMarketData = async () => {
const marketData = await getMarketData();
setData(marketData);
}
fetchMarketData();
}, [])
return (
<View style={styles.container}>
<View style={styles.titleWrap}>
<Text style={styles.largeTitle}>
Crypto
</Text>
<Divider width={1} style={styles.divider} />
</View>
<FlatList
keyExtractor={(item) => item.id}
data={data}
renderItem={({ item }) => (
<CryptoList
name={item.name}
symbol={item.symbol}
currentPrice={item.current_price}
priceChangePercentage={item.price_change_percentage_24h}
logoUrl={item.image}
/>
)}
/>
</View>
);
}
cryptoList.js
const CryptoList = ({ name, symbol, currentPrice, priceChangePercentage, logoUrl}) => {
const priceChangeColor = priceChangePercentage > 0 ? 'green' : 'red';
return (
<TouchableOpacity>
<View style={styles.itemWrapper}>
{/*Left side view*/}
<View style={styles.leftWrap}>
<Image source={{uri: logoUrl}} style={styles.image}/>
<View style={styles.titleWrapper}>
<Text style={styles.title}>{ name }</Text>
<Text style={styles.subtitle}>{ symbol.toUpperCase() }</Text>
</View>
</View>
{/*Right side view*/}
<View style={styles.rightWrap}>
<Text style={styles.title}>€{currentPrice.toLocaleString('de-DE', {currency: 'Eur'})}</Text>
<Text style={[styles.subtitle,{color: priceChangeColor} ]}>{priceChangePercentage.toFixed(2)}%</Text>
</View>
</View>
</TouchableOpacity>
)
}
import React, { useEffect, useState } from "react";
import { Text, View, StyleSheet, FlatList} from 'react-native';
import { Divider, useTheme } from 'react-native-elements';
import Constants from 'expo-constants';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import { HomeScreen } from './pages/homeScreen';
// You can import from local files
import CryptoList from './components/cyproList';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
import { getMarketData } from './components/cryptoApi';
const Stack = createNativeStackNavigator();
export default function App() {
const [data, setData] = useState([]);
const [selectedCoinData, setSelectedCoinData] = useState(null);
useEffect(() => {
const fetchMarketData = async () => {
const marketData = await getMarketData();
setData(marketData);
}
fetchMarketData();
}, [])
return (
<View style={styles.container}>
<View style={styles.titleWrap}>
<Text style={styles.largeTitle}>
Kriptovalūtu cenas
</Text>
<Divider width={1} style={styles.divider} />
</View>
<FlatList
keyExtractor={(item) => item.id}
data={data}
renderItem={({ item }) => (
<CryptoList
name={item.name}
symbol={item.symbol}
currentPrice={item.current_price}
priceChangePercentage={item.price_change_percentage_24h}
logoUrl={item.image}
/>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container:{
flex: 1,
backgroundColor: '#fff',
},
titleWrap:{
marginTop:50,
paddingHorizontal: 15,
},
largeTitle:{
fontSize: 22,
fontWeight: 'bold',
},
divider: {
marginTop: 10,
}
});
<!-- begin snippet: js hide: false console: true babel: false -->
<div data-snack-id="2OtINTPVy" data-snack-platform="android" data-snack-preview="true" data-snack-theme="light" style="overflow:hidden;background:#F9F9F9;border:1px solid var(--color-border);border-radius:4px;height:505px;width:100%"></div>
<script async src="https://snack.expo.dev/embed.js"></script>
your code seems incomplete. Have you tried wonPress={() => navigate(DetailsPage, {selectedCoinData})} where selectedCoinData is the details of your coin, then on details page you can retrieve the info with the params of react navigation with const route = useRoute() and use route.params.selectedCoinData
<FlatList
keyExtractor={(item) => item.id}
data={data}
renderItem={({ item }) => (
<CryptoList
name={item.name}
symbol={item.symbol}
currentPrice={item.current_price}
onPress={() => navigate(DetailsPage, {selectedCoinData})}
priceChangePercentage={item.price_change_percentage_24h}
logoUrl={item.image}
/>
)}
/>
and then in your component
const CryptoList = ({ name, symbol, currentPrice, priceChangePercentage, logoUrl, onPress}) => { return (
<TouchableOpacity onPress={onPress}>

How to render a Modal within a Tab Screen in React Navigation

I need to render a modal when the user press in the middle button. I'm using react-native-raw-bottom-sheet library to provide a Modal to my application.
I tried to pass a prop isFocused={props.navigation.isFocused} inside the <Tab.Screen> but the problem is when I pass the props to based if is or not focused in the the is rendered two times instead one.
I also tried to trigger the modal direct by the but without success.
My problematic is, when the user press the i need render the new that will contain the hole logic of the content in the modal and also will render the modal.
My tab.routes.js
import React from 'react';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import TabButton from '../components/Tab/Button';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Home from '../containers/Home';
import Adjustment from '../containers/Adjustment';
import Graphic from '../containers/Graphic';
import Help from '../containers/Help';
import NewTransaction from '../containers/NewTransaction';
const icons = {
Home: {
name: 'home',
},
Graphic: {
name: 'pie-chart',
},
NewTransaction: {
name: 'notifications-none',
},
Help: {
name: 'help-outline',
},
Adjustment: {
name: 'settings',
},
};
const Tab = createBottomTabNavigator();
const TabRoutes = () => (
<Tab.Navigator
initialRouteName="HomeScreen"
screenOptions={({route, navigation}) => ({
tabBarIcon: ({color, size, focused}) => {
if (route.name === 'NewTransaction') {
return <TabButton focused={focused} onPress={() => navigation.navigate('NewTransaction')} />;
}
const {name} = icons[route.name];
return <Icon name={name} size={size} color={color} />;
},
})}
tabBarOptions={{
keyboardHidesTabBar: true,
activeTintColor: '#f8b006',
inactiveTintColor: '#1C3041',
style: {
height: 60,
},
iconStyle: {
marginTop: 5,
},
labelStyle: {
fontSize: 12,
marginBottom: 10,
},
}}>
<Tab.Screen
options={{
title: 'Home',
}}
name="Home"
component={Home}
/>
<Tab.Screen
options={{
title: 'Gráfico',
}}
name="Graphic"
component={Graphic}
/>
<Tab.Screen
options={{
title: '',
}}
name="NewTransaction"
component={NewTransaction}
/>
<Tab.Screen
options={{
title: 'Ajuda',
}}
name="Help"
component={Help}
/>
<Tab.Screen
options={{
title: 'Ajustes',
}}
name="Adjustment">
{(props) => (
<Adjustment isVisible={props.navigation.isFocused()} onPress={() => props.navigation.navigate('Home')} />
)}
</Tab.Screen>
</Tab.Navigator>
);
export default TabRoutes;
Tab/Button/index.js
import React from 'react';
import {TouchableWithoutFeedback} from 'react-native-gesture-handler';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Button from './styles';
const TabButton = ({onPress, focused}) => {
return (
<TouchableWithoutFeedback onPress={onPress}>
<Button focused={focused}>
<Icon name="add" size={35} color={'white'} />
</Button>
</TouchableWithoutFeedback>
);
};
export default TabButton;
And the component that will display the modal content
import React from 'react';
import {Text, View} from 'react-native';
const NewTransaction = ({isVisible}) => {
return (
<View>
<Text>Welcome to NewTransactions </Text>
</View>
);
};
export default NewTransaction;
This is my home tab it looks like to you
I custom tab bar with code but the add button is not a screen it is just a button and popup options to select
import {hideModalCreate, showModalCreate} from '#features/loading/actions';
import CreateYCTV from '#features/main/CreateYCTV';
import HomeScreen from '#features/main/Home';
import Manager from '#features/main/Manager';
import Notification from '#features/main/Notification';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import images from '#res/icons';
import * as React from 'react';
import {Image, Pressable, View} from 'react-native';
import {Text, useTheme} from 'react-native-paper';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {connect} from 'react-redux';
import ProductStack from './ProductStack';
const Tab = createBottomTabNavigator();
function MyTabBar({
state,
descriptors,
navigation,
showModalCreate,
hideModalCreate,
isShowModalCreate,
}) {
const {colors} = useTheme();
const insets = useSafeAreaInsets();
const focusedOptions = descriptors[state.routes[state.index].key].options;
if (focusedOptions.tabBarVisible === false) {
return null;
}
return (
<View
style={{
flexDirection: 'row',
backgroundColor: '#FFFFFF',
paddingBottom: Math.max(insets.bottom, 0),
}}>
{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 getSourceImage = (isFocused) => {
switch (route.name) {
case 'home':
return isFocused ? images.tab_home1 : images.tab_home;
case 'loans':
return isFocused ? images.tab_searching1 : images.tab_searching;
case 'notification':
return isFocused ? images.notifications1 : images.notifications;
case 'manager':
return isFocused
? images.tab_paper_folder1
: images.tab_paper_folder;
default:
return images.tab_add;
}
};
const onPress = () => {
if (route.name === 'create') {
if (isShowModalCreate) {
hideModalCreate();
return;
}
showModalCreate();
return;
}
hideModalCreate();
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
};
return (
<Pressable
accessibilityRole="button"
accessibilityStates={isFocused ? ['selected'] : []}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID}
onPress={onPress}
onLongPress={onLongPress}
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 8,
backgroundColor: 'white',
}}>
<Image source={getSourceImage(isFocused)} />
{route.name != 'create' ? (
<Text
style={{
color: isFocused ? colors.primary : colors.placeholder,
fontSize: 10,
marginTop: 4,
}}>
{label}
</Text>
) : null}
</Pressable>
);
})}
</View>
);
}
const Tabbar = ({showModalCreate, hideModalCreate, isShowModalCreate}) => {
return (
<Tab.Navigator
tabBar={(props) => (
<MyTabBar
isShowModalCreate={isShowModalCreate}
showModalCreate={showModalCreate}
{...props}
hideModalCreate={hideModalCreate}
/>
)}>
<Tab.Screen
name="home"
component={HomeScreen}
options={{
title: 'Trang chủ',
}}
/>
<Tab.Screen
name="loans"
component={ProductStack}
options={{
title: 'Sản phẩm',
}}
/>
<Tab.Screen name="create" component={CreateYCTV} />
<Tab.Screen
name="notification"
component={Notification}
options={{
title: 'Thông báo',
tabBarBadge: '13',
}}
/>
<Tab.Screen
name="manager"
component={Manager}
options={{
title: 'Quản lý',
}}
/>
</Tab.Navigator>
);
};
const mapStateToProps = (state, ownProps) => {
return {
isShowModalCreate: state.loading.isShowModalCreate,
};
};
const mapDispatch = {
showModalCreate: showModalCreate,
hideModalCreate: hideModalCreate,
};
export default connect(mapStateToProps, mapDispatch)(Tabbar);

create a customized scrollable top Tab bar using react-navigation-tab?

i need to create a customized scrollable top tab bar using react navigation tabs and tabBarComponent without using any other third party library.
const TopTabBar = createMaterialTopTabNavigator({
Home: HomePage,
Entertainment: EntertainmentNews,
Business: BusinessStack,
Music: MusicStack,
Politics: PoliticsStack,
Sports: SportsStack,
Technology: TechnologyStack,
WorldNews: WorldNewsStack
}, {
tabBarComponent: (props) => <TopTabBarComponent {...props}/>
})
In this with tab bar component i am able to create the top bar but it does not scroll when the screen are swiped ?
import React , { Component } from 'react'
import { Text, View, StyleSheet, FlatList, TouchableOpacity, Animated, Dimensions} from 'react-native'
interface Props {
navigation?: any
}
interface State {
//
}
export class TopTabBarComponent extends Component <Props, State>{
flatListRef
constructor(props: Props, state: State){
super(props, state)
}
onPressItem = (index) => {
const { navigation } = this.props
navigation.navigate( this.props.navigation.state.routes[index].routeName )
// this.onScrollIndex(index)
}
renderTopBar = (item, index) => {
const routes = this.props.navigation.state.routes
const activeIndex = this.props.navigation.state.index
return (
<TouchableOpacity style = {{
alignItems: 'center' ,
height: 50,
justifyContent: 'center',
borderBottomWidth: activeIndex === index ? 2 : 0,
borderColor: 'green',
paddingHorizontal: 5
}} onPress = {() => this.onPressItem(index)}>
<Text style = {{ fontSize: 20, color: 'blue'}}>{item.routeName}</Text>
</TouchableOpacity>
)
}
render() {
// reactotron.log('this.props', this.props.navigation)
console.warn('this.props.navigation.state.index', this.props.navigation.state.index)
return(
<View style = {{ marginHorizontal: 5}}>
<FlatList
initialScrollIndex = { this.props.navigation.state.index }
ref = {(ref) => { this.flatListRef = ref}}
// style = {{ paddingHorizontal: 20}}
horizontal
showsHorizontalScrollIndicator = {false}
data = {this.props.navigation.state.routes}
renderItem = {({item , index}) => this.renderTopBar(item, index) }
ItemSeparatorComponent = {() => <View style = {{ paddingRight: 40}}/>}
/>
</View>
)
}
}
This is top tab bar component code ? So how can i make the top tab scroll automatically when the screens are swiped ?
This is a sample to my tab bar that I quickly edited for your test case.
function MyTabBar({ state, descriptors, navigation, position }) {
const scrollViewRef = useRef(null)
useEffect(() => {
scrollViewRef.current.scrollTo({ x: state.index * 50, y: 0, animated: true })
}, [state.index])
return (
<View style={styles.tabContainer}>
<ScrollView ref={list => scrollViewRef.current = list} contentContainerStyle={{ flexDirection: 'row', alignItems: 'center'}} horizontal>
{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 = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
};
let focusStyle = { }; //style object to append to the focussed tab
let tintColor = { };
let fontColor = { };
isFocused ? focusStyle = { backgroundColor: 'darkgray' } : focusStyle = { };
isFocused ? tintColor = { tintColor: 'black' } : tintColor = { tintColor: 'lightgray' }; // TODO: change this with proper fontColor codes
isFocused ? fontColor = { color: 'black' } : fontColor = { color: 'lightgray' };
//below controls the rendered tab
return (
<TouchableWithoutFeedback
key={index}
onPress={onPress}
onLongPress={onLongPress}
style={[styles.tabItem, focusStyle]}
>
<View style={styles.tabIconContainer}>
<LearnTabIcon title={route.name} color={tintColor} />
</View>
<Text style={[styles.labelStyle, fontColor]}>
{label}
</Text>
</TouchableWithoutFeedback>
);
})}
</ScrollView>
<View style={styles.tabBarIndicator}>
{ state.routes.map((route, index) => {
const isFocused = state.index === index;
let selectedStyle = { };
isFocused ? selectedStyle = { backgroundColor: 'darkgray'} : { }; // TODO: change this coloring to actual color codes
return (
<View
style={[styles.tabIndicators, selectedStyle]}
key={index}
>
</View>
);
})}
</View>
</View>
);
}
I'm using functional components for everything so it will look a bit different but in your custom tab bar grab the state.index on each index change and then use scrollToOffset to control where the scroll view is centered on screen. I put in a sample 50px offset scale just for simplicity.
I also wasn't using TypeScript but you seem to have most the boiler plate already ready to go anyway.
import React from 'react'
import {StatusBar} from 'react-native'
import {NavigationContainer} from '#react-navigation/native'
import {GestureHandlerRootView} from 'react-native-gesture-handler'
import {createMaterialTopTabNavigator} from '#react-navigation/material-top-tabs'
import HomeScreen from './screens/HomeScreen'
import LivingRoom from './screens/LivingRoom'
import Fav from './screens/Fav'
import Settings from './screens/Settings'
const Tab = createMaterialTopTabNavigator()
const AppRoot = () => {
return (
<GestureHandlerRootView className="flex-1">
<StatusBar hidden />
<NavigationContainer>
<Tab.Navigator
screenOptions={{
tabBarScrollEnabled: true,
tabBarIndicator: () => null,
tabBarStyle: {
backgroundColor: '#000',
},
tabBarItemStyle: {
width: 'auto',
alignItems: 'flex-start',
},
tabBarLabelStyle: {
fontSize: 30,
fontFamily: 'Satoshi-Black',
color: '#fff',
textTransform: 'capitalize',
},
}}
sceneContainerStyle={{backgroundColor: '#000'}}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Living Room" component={LivingRoom} />
<Tab.Screen name="Fav" component={Fav} />
<Tab.Screen name="Settings" component={Settings} />
</Tab.Navigator>
</NavigationContainer>
</GestureHandlerRootView>
)
}
export default AppRoot

React navigation hide one tab

I'm using react-navigation for navigating between screens. Is it possible to have createBottomTabNavigator with 3 tabs, but when you show tab bar, I want to have visible only 2 tabs instead of 3. ?
I made a npm package for this, please see;
https://www.npmjs.com/package/react-navigation-selective-tab-bar
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* #format
* #flow
*/
import React, { Component } from "react";
import { Platform, StyleSheet, Text, View, Button } from "react-native";
import { createBottomTabNavigator, createAppContainer } from "react-navigation";
import BottomTabBar from "react-navigation-selective-tab-bar";
class ScreenOne extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Screen One</Text>
<Text style={styles.number}>1</Text>
<Text style={styles.instructions}>
I AM on the bottom tab Navigator
</Text>
<View style={styles.buttons}>
<Button
title="One"
onPress={() => this.props.navigation.navigate("One")}
/>
<Button
title="Two"
onPress={() => this.props.navigation.navigate("Two")}
/>
<Button
title="Three"
onPress={() => this.props.navigation.navigate("Three")}
/>
<Button
title="Four"
onPress={() => this.props.navigation.navigate("Four")}
/>
</View>
</View>
);
}
}
class ScreenTwo extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Screen Two</Text>
<Text style={styles.number}>2</Text>
<Text style={styles.instructions}>
I am NOT on the bottom tab Navigator
</Text>
<View style={styles.buttons}>
<Button
title="One"
onPress={() => this.props.navigation.navigate("One")}
/>
<Button
title="Two"
onPress={() => this.props.navigation.navigate("Two")}
/>
<Button
title="Three"
onPress={() => this.props.navigation.navigate("Three")}
/>
<Button
title="Four"
onPress={() => this.props.navigation.navigate("Four")}
/>
</View>
</View>
);
}
}
class ScreenThree extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Screen Three</Text>
<Text style={styles.number}>3</Text>
<Text style={styles.instructions}>
I AM on the bottom tab Navigator
</Text>
<View style={styles.buttons}>
<Button
title="One"
onPress={() => this.props.navigation.navigate("One")}
/>
<Button
title="Two"
onPress={() => this.props.navigation.navigate("Two")}
/>
<Button
title="Three"
onPress={() => this.props.navigation.navigate("Three")}
/>
<Button
title="Four"
onPress={() => this.props.navigation.navigate("Four")}
/>
</View>
</View>
);
}
}
class ScreenFour extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Screen Four</Text>
<Text style={styles.number}>4</Text>
<Text style={styles.instructions}>
I am NOT on the bottom tab Navigator
</Text>
<View style={styles.buttons}>
<Button
title="One"
onPress={() => this.props.navigation.navigate("One")}
/>
<Button
title="Two"
onPress={() => this.props.navigation.navigate("Two")}
/>
<Button
title="Three"
onPress={() => this.props.navigation.navigate("Three")}
/>
<Button
title="Four"
onPress={() => this.props.navigation.navigate("Four")}
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5FCFF"
},
welcome: {
fontSize: 20,
textAlign: "center",
margin: 10
},
instructions: {
textAlign: "center",
color: "#333333",
marginBottom: 5
},
number: {
fontSize: 50
},
buttons: {
flexDirection: "row"
}
});
const AppNavigator = createBottomTabNavigator(
{
One: {
screen: ScreenOne
},
Two: {
screen: ScreenTwo
},
Three: {
screen: ScreenThree
},
Four: {
screen: ScreenFour
}
},
{
tabBarComponent: props => {
return (
<BottomTabBar
{...props} // Required
display={["One", "Three"]} // Required
background="black" // Optional
/>
);
}
}
);
export default createAppContainer(AppNavigator);
https://github.com/react-navigation/react-navigation/issues/5230#issuecomment-649206507
Here is how you can tell the tab navigator to not render certain routes.
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarButton: [
"Route1ToExclude",
"Route2ToExclude"
].includes(route.name)
? () => {
return null;
}
: undefined,
})}
>
This worked for me, you are still able to navigate to the tab! I changed it to this:
Without a variable:
tabBarButton: ["About"].includes(route.name) ? () => null : undefined
With a variable to hide specific tabs:
const hiddenTabs = ["About", "Food"];
tabBarButton: hiddenTabs.includes(route.name) ? () => null : undefined
With a variable to show specific tabs only:
const tabsToShow = ["About", "Food"];
tabBarButton: !tabsToShow.includes(route.name) ? () => null : undefined
All credit goes to Ben Awad!
Put your third item/screen in a stack navigator:
const Bottom = createBottomTabNavigator({
item1: {screen: Screen1},
item2: {screen: Screen2},
},{
initialRouteName: "item1",
}
)
export default createStackNavigator({
tabs: Bottom,
item3: Screen3,
})
At last, to change the screen to your third route in your component, you can do this:
// ...
import {withNavigation} from 'react-navigation' // IMPORTANT
export default class Example extends React.Component{
render(){
return(
<TouchableOpacity onPress={() => this.props.navigation.navigate('item3')}>
)
}
}
export default withNavigation(Example) // IMPORTANT
For example, if you want to have 5 active routes in a createBottomTabNavigator, but only 3 or another number to show icons in the TabBar. In this case, all 5 routes will be active, and you can go to them props.navigation.navigate()
You must pass a filtered list of routes to the TabBar component, but the object must be sure to be deeply copied (using lodash for example)
import cloneDeep from 'lodash/cloneDeep';
....
const TabBarComponent = props => {
const routeNamesToHide = [
'MyOfficeStack',
'ArenaStack',
'SavedSearchesStack',
'NotificationsStack',
];
// Delete from TABBAR items in array 'routeNamesToHide'
let newNavigation = cloneDeep(props.navigation);
newNavigation.state.routes = newNavigation.state.routes.filter(
item => !routeNamesToHide.includes(item.routeName)
);
//
return <BottomTabBar {...props} navigation={{ ...newNavigation }} />;
};
const tabNavigator = createBottomTabNavigator(
{
SearchStack,
FavouritesStack,
AddScreenStack,
MessagesStack,
BookingsStack,
MyOfficeStack,
AreaStack,
SavedSearchesStack,
NotificationsStack,
},
{
lazy: false,
tabBarOptions: {
showLabel: true,
},
tabBarComponent: props => (
<TabBarComponent {...props} />
),
}
);
the easiest solution is this
<Tab.Screen
name='someroute'
component={SomeComponent}
options={{
tabBarButton: props => null,
}}
/>
this is by far the best solution because it doesn't require extra effort
Ben Awad solution(mentioned by Kayden van Rijn) is good, it allows centralized control, but you need extra effort to make sure the type of the route name array is correct
<Tab.Navigator
screenOptions={({ route }) => {
const toExclude: typeof route.name[] = ['routeName']
return {
tabBarButton: toExclude.includes(route.name)
? () => {
return null
}
: undefined,
}
}}
>
credit

How to change the color of active tab ? (tab is custom)

I am using react-navigation in RN v 0.46.1 project
I have used customTabs from example directory of react-navigation.
I want to change the color of the tab when active .
I've tried to pass ans use navigationOptions but no success.
Also , Tabs are displayed at top , I want them at bottom.
import React, { Component } from "react";
import { AppRegistry, Button,
Platform,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View } from "react-native";
import { createNavigator,
createNavigationContainer,
TabRouter,
addNavigationHelpers } from 'react-navigation'
import Chats from './Chats'
import Contacts from './Contacts'
const MyNavScreen = ({ navigation, banner }) => (
<ScrollView>
<Text>banner</Text>
<Button
onPress={() => {
navigation.goBack(null);
}}
title="Go back"
/>
</ScrollView>
);
const MySettingsScreen = ({ navigation }) => (
<MyNavScreen banner="Settings Screen" navigation={navigation} />
);
const CustomTabBar = ({ navigation }) => {
const { routes } = navigation.state;
return (
<View style={styles.tabContainer}>
{routes.map(route => (
<TouchableOpacity
onPress={() => navigation.navigate(route.routeName)}
style={styles.tab}
key={route.routeName}
>
<Text>{route.routeName}</Text>
</TouchableOpacity>
))}
</View>
);
};
const CustomTabView = ({ router, navigation }) => {
const { routes, index } = navigation.state;
const ActiveScreen = router.getComponentForState(navigation.state);
const routeNav = addNavigationHelpers({
...navigation,
state: routes[index],
});
const routeOptions = router.getScreenOptions(routeNav, 'tabBar');
console.log(routeOptions.headerTintColor);
return (
<View style={styles.container}>
<CustomTabBar navigation={navigation} />
<ActiveScreen
navigation={addNavigationHelpers({
...navigation,
state: routes[index],
})}
/>
</View>
);
};
const CustomTabRouter = TabRouter(
{
Friends: {
screen: Chats,
path: '',
},
Status: {
screen: Contacts,
path: 'notifications',
},
Other: {
screen: MySettingsScreen,
path: 'settings',
},
},
{
initialRouteName: 'Friends',
},
);
const CustomTabs = createNavigationContainer(
createNavigator(CustomTabRouter)(CustomTabView)
);
const styles = StyleSheet.create({
container: {
marginTop: Platform.OS === 'ios' ? 20 : 0,
},
tabContainer: {
flexDirection: 'row',
height: 48,
},
tab: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
margin: 4,
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 4,
backgroundColor:'white'
},
});
export default CustomTabs;
AppRegistry.registerComponent('awsm', () => CustomTabs);
Compare the active tab's routeName in map and add style like
style={[(this.props.activeRouteName == route.routeName) ? styles.activeTab : styles.tab]}
For styling tabs at bottom you can use ScrollView in parent view and then your tabs so, it will be something like this
<View style={flex:1}>
<ScrollView>
// your page content
</ScrollView>
<Tabs/>
</View>
By using scrollview you will be able to force the tabs at bottom.
Can't you achieve what you want with the default TabNavigator ?
In the docs you can pass a TabBarComponent to the TabNavigator and set tabBarPosition - position of the tab bar, can be 'top' or 'bottom' to bottom so your tabBar will be at the bottom.
If you still want to do all that yourself, I guess :
To align the TabBar on the bottom, you could put { position: 'absolute', bottom: 0 } on the TabBar style
To change the color of your focused Tab, you could do:
const CustomTabBar = ({ navigation }) => {
const { routes, index } = navigation.state;
const isFocused = routes[index].routeName == route.routeName; // Not totally sure about the condition there, but you get the idea?
return (
<View style={styles.tabContainer}>
{routes.map(route => (
<TouchableOpacity
onPress={() => navigation.navigate(route.routeName)}
style={[styles.tab, isFocused ? styles.focusedTab : null]}
key={route.routeName}
>
<Text>{route.routeName}</Text>
</TouchableOpacity>
))}
</View>
);
};
?