I created a simple tab navigation for a React Native app using react-navigation. It works fine, but I can't seem to adjust the height of it. It'll only go to a max of about 80, I need it to be about 150% of the current height, maybe double.
Does anyone know how to increase the height of the tab nav (preferably without creating about 6 more js files? ) I only have a limited period to fix it as I'd like.
Below is the nav code as-is
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { createBottomTabNavigator, createAppContainer } from "react-navigation";
import HomeScreen from './screens/HomeScreen';
import AboutScreen from './screens/AboutScreen';
import SettingsScreen from './screens/SettingsScreen';
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
const AppNavigator = createBottomTabNavigator({
Home: {
screen: HomeScreen
},
About: {
screen: AboutScreen
},
Settings: {
screen: SettingsScreen
}
}, {
initialRouteName: "Home"
});
const AppContainer = createAppContainer(AppNavigator);
Thanks
As said in the docs, you just need to add screenOptions={tabBarStyle:{height:100}}
For example:
bottomNavigatorConfigs = {
initialRouteName: "HomeScreen",
screenOptions: {
tabBarStyle: { height: 300 },
},
};
This is an example of the bottomNavigatorConfigs (tested) and working.
Where bottomNavigatorConfigs is used like this:
createBottomTabNavigator(bottomRoutesConfig, bottomNavigatorConfigs);
Source: https://reactnavigation.org/docs/bottom-tab-navigator/#options
Be careful with an iPhone's home indicator as you need to take account of the extra space at the bottom of the iPhone when setting absolute height.
import { useSafeAreaInsets } from 'react-native-safe-area-context';
...
export const Navigation = () => {
const insets = useSafeAreaInsets();
return (
<NavigationContainer>
<Tab.Navigator
tabBarOptions={{
style: {
height: 60 + insets.bottom,
...
},
tabStyle: {
height: 60,
...
},
...
}}>
...
tabBarOptions: {
style: {
height: '50%',
}
}
try that may be working.
With react navigation 6 you can just use:
tabBarStyle : {
height: 150,
...
}
screenOptions={
{
headerShown:false,
tabBarActiveTintColor:Colors.primary,
tabBarInactiveTintColor:Colors.primary2,
tabBarStyle: { height: 60 }
}
}
Related
I am trying to migrate from react-native-navigation v1 to react-native-navigation v2. I am struggling to move from
Navigation.startSingleScreenApp
to
Navigation.setRoot
When I switch from Navigation.startSingleScreenApp (v1) to Navigation.setRoot (v2), I no longer have the navigator prop that I was relying on to navigate around the application.
I have copy and pasted all relevant code below
RegisterScreens
import { Navigation } from 'react-native-navigation';
import SplashScreenScreen from './components/SplashScreen';
import { Provider } from 'react-redux';
import React from "react";
import SCREEN from './screenNames';
export default function registerScreens(store) {
Navigation.registerComponent(
SCREEN.SPLASH_SCREEN,
() => props => (<Provider store={store}><SplashScreenScreen {...props} /></Provider>), () => SplashScreenScreen);
App
import { Platform } from 'react-native';
import { Navigation } from 'react-native-navigation';
import registerScreens from './registerScreens';
import { Colors, Fonts } from './themes';
import { store } from './configureStore';
import NavigationListener from './NavigationEventListener';
import configureNotification from './configureNotification';
import SCREEN from './screenNames';
import Reactotron from 'reactotron-react-native';
const navBarTranslucent = Platform.OS === 'ios';
configureNotification();
registerScreens(store);
new NavigationListener(store);
const STARTING_SCREEN = SCREEN.SPLASH_SCREEN;
Navigation.events().registerAppLaunchedListener(() => {
Reactotron.log('5');
Navigation.setRoot({
root: {
stack: {
children: [{
component: {
id: STARTING_SCREEN,
name: STARTING_SCREEN
}
}],
}
},
layout: {
orientation: 'portrait',
},
});
});
SplashScreen
import React from 'react';
import { View, StyleSheet, Text } from 'react-native';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { PersistGate } from 'redux-persist/es/integration/react';
import { navigateToFirstScreen } from '../redux/splash';
import { Colors, Fonts, Metrics } from '../themes';
import { persistor } from '../configureStore';
export class SplashScreen extends React.Component {
navigateTo = (screen) =>
this.props.navigator.push({
screen,
overrideBackPress: true,
backButtonHidden: true,
animated: false,
navigatorStyle: {
disabledBackGesture: true,
},
});
render() {
const { dispatchNavigateToFirstScreen } = this.props;
return (
<PersistGate
persistor={persistor}
onBeforeLift={() => setTimeout(() => dispatchNavigateToFirstScreen(this.navigateTo), 2000)}><View style={styles.bodyContainer}
>
<Text>Jono</Text>
</View>
</PersistGate>
);
}
}
const styles = StyleSheet.create({
bodyContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: Colors.splashScreen,
},
appTitleText: {
fontSize: Fonts.size.splashScreenTitle,
fontFamily: Fonts.type.extraBold,
lineHeight: Metrics.lineHeight.appTitle,
textAlign: 'center',
color: Colors.textLightColor,
},
});
SplashScreen.propTypes = {
navigator: PropTypes.shape({
push: PropTypes.func.isRequired,
}).isRequired,
dispatchNavigateToFirstScreen: PropTypes.func.isRequired,
};
const mapDispatchToProps = (dispatch) => {
return {
dispatchNavigateToFirstScreen: (navigateTo) =>
dispatch(navigateToFirstScreen(navigateTo)),
};
};
export default connect(null, mapDispatchToProps)(SplashScreen);
I spent multiple hours trying to solve this problem so I am going to post my conclusion as an answer.
this.props.navigator is not used anymore in 2.x.
You need to use Navigation
This dude had the same problem and reached the same conclusion: https://github.com/wix/react-native-navigation/issues/3795
In my project, after updating node modules, react navigation showed some issues. In the console it says,
The tabBarBottom is deprecated. Use react-navigation-tabs package.
stackNavigator function name is deprecated. Use createStackNavigator
tabNavigator is deprecated. Use createBottomTabNavigator
import React from "react";
import { StackNavigator } from "react-navigation";
import { TabNavFooter } from "./TabNavFooter";
import { SIGNIN_KEY, SIGNUP_KEY } from "../config/routeKeys";
import {
SignupScreen,
SigninScreen,
MainFeedScreen,
CommentScreen,
SharePostScreen
} from "../screens";
export const Routes = StackNavigator({
mainfeed: { screen: TabNavFooter },
signin: { screen: SigninScreen },
signup: { screen: SignupScreen },
comments: { screen: CommentScreen },
sharePost: { screen: SharePostScreen }
});
import React from "react";
import { TabNavigator, TabBarBottom } from "react-navigation";
import { ClickableImage, ClickableIcon } from "../mixing/UI";
import TAB_NAVIGATOR_IMAGES from "../config/tabNavImgs";
import { Image } from "react-native";
import {
MainFeedScreen,
WorkoutScreen,
VideosScreen,
ChatScreen,
ProfileMainScreen
} from "../screens";
export const TabNavFooter = TabNavigator(
{
mainfeed: { screen: MainFeedScreen },
workout: { screen: WorkoutScreen },
video: { screen: VideosScreen },
chat: { screen: ChatScreen },
profile: { screen: ProfileMainScreen }
},
{
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let imageSource;
if (routeName === "mainfeed") {
imageSource =
TAB_NAVIGATOR_IMAGES[
`${focused ? "mainfeedActive" : "mainfeedInactive"}`
];
} else if (routeName === "workout") {
imageSource =
TAB_NAVIGATOR_IMAGES[
`${focused ? "workoutActive" : "workoutInactive"}`
];
} else if (routeName === "video") {
imageSource =
TAB_NAVIGATOR_IMAGES[
`${focused ? "videoActive" : "videoInactive"}`
];
} else if (routeName === "chat") {
imageSource =
TAB_NAVIGATOR_IMAGES[`${focused ? "chatActive" : "chatInactive"}`];
} else if (routeName === "profile") {
imageSource =
TAB_NAVIGATOR_IMAGES[
`${focused ? "profileActive" : "profileInactive"}`
];
}
return (
<Image
source={imageSource}
style={{
width: 25,
height: 25,
tintColor: tintColor,
marginBottom: 0
}}
/>
);
}
}),
tabBarComponent: TabBarBottom,
tabBarPosition: "bottom",
tabBarOptions: {
activeTintColor: "blue",
inactiveTintColor: "gray"
},
swipeEnabled: false,
lazyLoad: true,
animationEnabled: false
}
);
How can I solve these errors?
It's due to upgrade in react-navigation version. you have probably upgraded to v2 of the package.
They have documentation for that version but still not complete and lack in some minute details. you can see the doc in this link
the configuration differs between v1 and v2. you could manage to get v2 work with some difficulties. you can ask specific difficulties you face in that process here or in some other question. But if you find still tough, you can move back to lower version which is well documented.
Replace StackNavigator with createStackNavigator. And TabNavigator with createBottomTabNavigator.
TabBarBottom I have not used yet, but it looks like it was put into its own package called react-navigation-tabs that needs to be installed and pulled from there instead.
Dependencies version:
"dependencies": {
"react": "16.3.1",
"react-native": "~0.55.2",
"react-navigation": "^2.0.1",
}
I use react-navigation to navigate my screen, i create two screen and a drawer
Router.js:
import { createStackNavigator, createDrawerNavigator } from 'react-navigation';
import MainActivity from './components/MainActivity';
import ThisWeek from './components/ThisWeek';
import DrawerPanel from './components/DrawerPanel';
const Stack = createStackNavigator({
MainActivity: {
screen: MainActivity,
navigationOptions: {
title: 'Welcome',
headerStyle: {
backgroundColor: '#81A3A7',
elevation: null
}
}
},
ThisWeek: {
screen: ThisWeek
}
},
{
initialRouteName: 'MainActivity'
}
);
const Router = createDrawerNavigator({
FirstScreen: {
screen: Stack
}
},
{
contentComponent: DrawerPanel,
drawerWidth: 200
});
export default Router;
In my DrawerPanel.js i can click the two button navigate to the screen, but when i try to use this.props.navigation.closeDrawer(); that shows an error _this2.props.navigation.closeDrawer is not a function.
So i try to console.log(this.props);,i can see openDrawer and closeDrawer under navigation
Here is my DrawerPanel.js:
import React, { Component } from 'react';
import { ScrollView, FlatList, Text } from 'react-native';
import { View } from 'react-native-animatable';
import { List, Button } from 'react-native-elements';
class DrawerPanel extends Component {
render() {
console.log(this.props);
return (
<ScrollView style={{ backgroundColor: '#81A3A7' }}>
<Button
onPress={() => {
this.props.navigation.actions.closeDrawer();
this.props.navigation.navigate('MainActivity');
}}
backgroundColor={'#81A3A7'}
containerViewStyle={{ width: '100%', marginLeft: -61 }}
title='Main page'
/>
<Button
onPress={() => this.props.navigation.navigate('ThisWeek')}
backgroundColor={'#81A3A7'}
containerViewStyle={{ width: '100%', marginLeft: -46 }}
title='This weel'
/>
</ScrollView>
);
}
}
export default DrawerPanel;
I can't figure it out why i can use this.props.navigation.navigate(); to another screen not allow to use this.props.navigation.closeDrawer();
I try make a change to use this.props.navigation.actions.closeDrawer(); the error will show Cannot read property 'closeDrawer' of undefined.
What step i make it wrong ? Any help would be appreciated. Thanks in advance.
Try this
import { DrawerActions } from 'react-navigation';
this.props.navigation.dispatch(DrawerActions.closeDrawer());
this.props.navigation.dispatch(DrawerActions.openDrawer());
You are using both StackNavigator and DrawrNavigator so that the way to use them is different a little bit.
Keep in mind we have two version for react-navigation (v1 and v2) for now so that you should read the documentation carefully.
Please try using this:
Close drawer
this.props.navigation.navigate('DrawerClose'); // for version 1
this.props.navigation.openDrawer(); // for version 2
Open drawer:
this.props.navigation.navigate('DrawerOpen'); // for version 1
this.props.navigation.closeDrawer(); // for version 2
Be careful for reference any bugs fix for this libraries on the internet which you have to know which version is using in.
Note that the order of nesting - if the stack navigator is not inside of the drawer, it will not have the openDrawer function.
I guess it will work for you in this case.
Cheer!
In your DrawerPanel file. You did not use the constructor. Hence, your component's props did not know about the navigation props that the DrawerNavigator passed in. Try putting this before your render function in the component.
constructor(props){
super(props);
}
This way you will no longer need to use dispatch(), but instead use openDrawer() and closeDrawer().
The maintainers of react-navigation have removed 'lazy: true' from the library, causing all tabs to attempt to render at once (and fetches previously controlled by lazy now firing out of order).
In order to maintain similar functionality, how do you force a wait on a tab screen to not load or call fetch calls prior to being focused for the first time?
It seems they did remove it, but have decided to add it back in v 1.1.2
https://github.com/react-navigation/react-navigation/releases/tag/v1.1.2
Thus, you should be able to pass lazy={true} in your TabNavigatorConfig object, and then tabs will not be rendered before they are active. To further optimize memory usage, you can couple this with removeClippedSubviews to free memory from inactive tabs.
You can use LazyLoading from react-navigation-utils
React-navigation now suports withNavigationFocus wrapper.
You can use it to wrap the screen you want to prevent updating when it is not focused.
import React from 'react';
import { Text } from 'react-native';
import { withNavigationFocus } from 'react-navigation';
class LazyScreen extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return nextProps.isFocused;
}
render() {
return <Text>{this.props.isFocused ? 'Focused' : 'Not focused' </Text>;
}
}
export default withNavigationFocus(LazyScreen);
P.S. if you use Redux just do
export default connect(mapStateToProps, mapDispatchToProps)(withNavigationFocus(LazyScreen));
lazy={true}
optimizationsEnabled={true}
tabBarOptions={tabBarOptions}
the above code is important, try it
import { createMaterialTopTabNavigator } from "#react-navigation/material-top-tabs";
import { createStackNavigator } from "#react-navigation/stack";
const TabNavigator = createMaterialTopTabNavigator();
const Stack1 = createStackNavigator();
const Stack2 = createStackNavigator();
const ProductsScreen = (props) => {
//
return (
<TabNavigator.Navigator
lazy={true}
optimizationsEnabled={true}
tabBarOptions={tabBarOptions}
>
<TabNavigator.Screen name="HOME" component={StackScreen1} />
<TabNavigator.Screen name="SHOP" component={StackScreen2} />
</TabNavigator.Navigator>
);
};
const tabBarOptions = {
indicatorStyle: {
height: null,
top: 0,
backgroundColor: "#ccc",
borderBottomColor: "black",
borderBottomWidth: 3,
},
activeTintColor: "black",
style: {
backgroundColor: "red",
},
labelStyle: { fontSize: 13 },
};
How about this?
const MyTab = TabNavigator({
tab1:{screen:TabScreen1},
tab2:{screen:TabScreen2}
}
class MainScreen extends React.Component{
constructor(){
super();
this.state = {
loading:true
}
}
componentWillMount(){
//fetch login
//set loading:false when fetch is done
}
render(){
!this.state.loading && <MyTab/>
}
}
In the new versions of React Navigation the lazy prop is set to true by default.
See https://reactnavigation.org/docs/en/bottom-tab-navigator.html#lazy
I am new to react native, and I am struggling to understand it. This may be a very basic question.
I have a screen and it consists of a searchbar on top of the page and below it there are Tabs. While navigating through the tabs, the searchbar should not be removed (being at the top level).
MainScreen:
export default class MainScreen extends Component {
render() {
return (
<View>
<Text>My search bar here</Text>
<TabBar></TabBar>
</View>
);
}
}
TabBar:
const routeConfiguration = {
TabEvents: { screen: TabEvents },
TabPeople: { screen: TabPeople },
TabGroups: { screen: TabGroups },
TabMap: { screen: TabMap },
}
const tabBarConfiguration = {
tabBarOptions:{
// some options
}
}
export const TabBar = TabNavigator(routeConfiguration,tabBarConfiguration)
When running the app, only the text is being displayed My search bar here without the tabs.
To be able to show tabs, the navigator acts like a container with "two views". One is for the screens that you wanna show and, at the bottom, the tabs container.
So, for the MainScreen you just only need to define the tabs/screens that want react navigator to render.
In each screen you will put the header as shown above. You could also define a default header in the navigator props.
MainScreen.js:
const MainScreen = TabNavigator({
TabEvents: { screen: TabEvents },
Second: { screen: SecondPage },
Third: { screen: ThirdPage },
Fourth: { screen: FourthPage },
Fifth: { screen: FifthPage }
}
})
export default MainScreen;
MainScreen.js: (with default header)
const MainScreen = TabNavigator({
TabEvents: { screen: TabEvents },
Second: { screen: SecondPage },
Third: { screen: ThirdPage },
Fourth: { screen: FourthPage },
Fifth: { screen: FifthPage }
}, {
navigationOptions: {
header: <YourHeader />
}
})
export default MainScreen;
TabEvents.js
export default class TabEvents extends Component {
render() {
return (
<View>
<YourHeader />
<MoreStuff/>
</View>
);
}
}
You wil have a more detailed example in the docs ( https://github.com/react-community/react-navigation/blob/master/examples/NavigationPlayground/js/SimpleTabs.js & https://reactnavigation.org/docs/navigators/tab)
You can wrap your TabNavigator with StackNavigator.
MyTabNavigator.js
const MyTabNavigator = TabNavigator({
ScreenX: { screen: SceenNameX },
ScreenY: { screen: ScreenNameY }
}, {
initialRouteName: 'ScreenX',
tabBarPosition: 'top',
tabBarOptions: {
activeTintColor: '#af0'
}
})
export default MyTabNavigator
MainScreen.js
export default class MainScreen extends Component {
static navigationOptions = {
header: (props) => (
<SearchBar {...props}/>
)
}
render() {
return (
<MyTabNavigator />
)
}
}
MyStackNavigator.js
const MyStackNavigator = StackNavigator({
Main: { screen: MainScreen }
}, {
initialRouteName: 'Main'
})
export default MyStackNavigator
Now you can call MyStackNavigator to load MainScreen which will render the header SearchBar and the body MyTabNavigator.
The way to create a Tab navigator is the following:
tabNavigator.js
import React from 'react'
import { Platform } from 'react-native'
import { TabNavigator, StackNavigator } from 'react-navigation'
const Tabs = TabNavigator({
Home:{ //this is the name of the screen, by default the first screen that you want to show is called Home
screen: component , //this is the component that you want to show in the screen
navigationOptions: {
tabBarLabel: 'some label', //this will be located as a title for the tab
tabBarIcon: ({ tintColor }) => <i> some icon </i>, //this allow you to show a icon in the tab
//the following options are to customize the header, maybe you don't need this.
title: 'some title',
headerStyle:{
backgroundColor: 'blue' // color for the header
},
headerTitleStyle:{
color: 'white' // color for the text on the header
},
header: <YourHeader/>
}
},
// if you need add some other tab repeat the same pattern here OtherScreen:{ ...}
},{
//this are options to customize the tab itself, I added some good ones.
tabBarOptions: {
activeTintColor: Platform.OS === 'ios' ? primary : white,
style:{
height:40,
backgroundColor: Platform.OS === 'ios' ? white : primary,
shadowRadius: 6,
shadowOpacity: 1,
shadowColor: 'rgba(0,0,0,0.24)',
shadowOffset: {
width: 0,
height: 3
}
}
}
})
export default Tabs
mainScreen.js
import React, { Component} from 'react'
import Tabs from './tabNavigator'
export default class MainScreen extends Component {
render() {
return (
<View>
<Tabs/>
</View>
);
}
}
I hope it helps.