React-native application with version:
react#16.9.0
react-native#0.61.2
react-navigation#^4.0.10
react-navigation-stack#^1.10.3
react-navigation-tabs#^2.5.6
I'm trying to make an application with createBottomTabs, when i try to type in TextInput, when the keyboard show, there are bottomtabs with icon, the icon will auto hide, leaving the white space / gap behind on top of the keyboard
my code example :
<SafeAreaView style={
flex: 1,
alignItems: 'center'
}>
<View>
<TextInput />
</View>
</SafeAreaView>
already tried to change SafeAreaView with KeyboardAvoidingView, but the white space/gap is still there.
const MainTabs = createBottomTabNavigator({
Screen1: {
screen: Screen1Stack,
navigationOptions: {
tabBarIcon: Icon
}
},
Screen2: {
screen: Screen2Screen,
navigationOptions: {
tabBarIcon: Icon
}
},
Screen3: {
screen: Screen3Screen,
navigationOptions: {
tabBarIcon: Icon
}
},
Screen4: {
screen: Screen4Screen,
navigationOptions: {
tabBarIcon: Icon
}
},
},
{
tabBarOptions: {
...
showLabel: false
}
}
)
i get the answer from the comment at react navigation tabs github (with title "Bottom tab bars and keyboard on Android #16"), and i will share it here, incase someone experiencing a same issue as me, its answered by #export-mike and detailed by #hegelstad
import React from 'react';
import { Platform, Keyboard } from 'react-native';
import { BottomTabBar } from 'react-navigation-tabs'; // need version 2.0 react-navigation of course... it comes preinstalled as a dependency of react-navigation.
export default class TabBarComponent extends React.Component {
state = {
visible: true
}
componentDidMount() {
if (Platform.OS === 'android') {
this.keyboardEventListeners = [
Keyboard.addListener('keyboardDidShow', this.visible(false)),
Keyboard.addListener('keyboardDidHide', this.visible(true))
];
}
}
componentWillUnmount() {
this.keyboardEventListeners && this.keyboardEventListeners.forEach((eventListener) => eventListener.remove());
}
visible = visible => () => this.setState({visible});
render() {
if (!this.state.visible) {
return null;
} else {
return (
<BottomTabBar {...this.props} />
);
}
}
}
Usage :
const Tabs = createBottomTabNavigator({
TabA: {
screen: TabA,
path: 'tab-a',
navigationOptions: ({ navigation }) => ({
tabBarLabel: 'Tab A',
})
},
TabB: {
screen: TabB,
path: 'tab-b',
navigationOptions: ({ navigation }) => ({
tabBarLabel: 'Tab B',
})
}
},
(Platform.OS === 'android')
? {
tabBarComponent: props => <TabBarComponent {...props} />,
tabBarPosition: 'bottom'
}
: {
// don't change tabBarComponent here - it works on iOS after all.
}
);
Related
I want to display bottom tab tar in react-navigation 4, but there is no luck to make it happen, even I use it. Can anyone help me to find the problem with my code or which option should I use?
static navigationOptions = {
title: "Map",
tabBarIcon: ({ tintColor }) => {
return <Icon name="home" size={30} color={tintColor} />;
}
}
in any component screen, it does still not work.
Here is my router
I want to apply the bottom tab icon to homescreen
const MainAuthenticated = createAppContainer(
createBottomTabNavigator(
{
main: {
screen: createBottomTabNavigator({
Marketplace: {
screen: createStackNavigator({
home: {
screen: HomeScreen,
},
profile: { screen: Profile },
business: { screen: MyBusiness },
logout: { screen: Logout },
itemlist: { screen: ItemList },
itemcreate: { screen: ItemCreate },
itemdetail: { screen: ItemDetail },
businesscreate: { screen: BusinessCreate },
businessdetail: { screen: MyBusinessDetail },
}),
},
XOrders: { screen: OrderScreen },
Favorite: { screen: FavoriteScreen },
}),
},
},
{
defaultNavigationOptions: {
tabBarVisible: false,
},
},
),
);
Here is the working code to add the bottom tab bar icon in react-navigation v4
import Ionicons from 'react-native-vector-icons/Ionicons';
import { createAppContainer } from 'react-navigation';
import { createBottomTabNavigator } from 'react-navigation-tabs';
export default createBottomTabNavigator(
{
Home: HomeScreen,
Settings: SettingsScreen,
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
let IconComponent = Ionicons;
let iconName;
if (routeName === 'Home') {
iconName = focused
? 'ios-information-circle'
: 'ios-information-circle-outline';
// Sometimes we want to add badges to some icons.
// You can check the implementation below.
IconComponent = HomeIconWithBadge;
} else if (routeName === 'Settings') {
iconName = focused ? 'ios-list-box' : 'ios-list';
}
// You can return any component that you like here!
return <IconComponent name={iconName} size={25} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
}
);
If you wanted to use some .png or jpeg or some other image file instead of vector icons just replace this
<IconComponent name={iconName} size={25} color={tintColor} /> // replace this with below
<Image source={require('your image path')} style={{height: 30, width: 30}} />
I have made my custom header and i want to remove react-native default header.
I have tried with
Setting option "header: null" in navigationOptions of
createBottomTabNavigator
header:null in HomeScreen.js file
but it's not working. Please help to solve this issue. Here is my navigation code. I am attaching screenshot exactly what i want to remove.
import React from "react";
import { Platform } from "react-native";
import { createStackNavigator } from "react-navigation-stack";
import { createBottomTabNavigator } from "react-navigation-tabs";
import TabBarIcon from "../components/TabBarIcon";
import HomeScreen from "../screens/HomeScreen";
import SavedScreen from "../screens/SavedScreen";
import BookingScreen from "../screens/BookingScreen";
import BeAHostScreen from "../screens/BeAHostScreen";
import ReferEarnScreen from "../screens/ReferEarnScreen";
import BookingInnerScreen from "../screens/BookingInnerScreen";
import { Icon } from "react-native-elements";
const config = Platform.select({
web: { headerMode: "screen" },
default: {}
});
const tabNavigator = createBottomTabNavigator({
Home: {
screen: HomeScreen,
defaultNavigationOptions: {
title: "App Name Here"
},
navigationOptions: {
tabBarLabel: "Home",
tabBarOptions: {
activeTintColor: "#00E8AC"
},
tabBarIcon: ({ focused }) => {
return focused ? (
<Icon name="md-home" type="ionicon" color="#00E8AC" />
) : (
<Icon name="md-home" type="ionicon" color="#ccc" />
);
}
}
},
Saved: {
screen: SavedScreen,
defaultNavigationOptions: {
title: "Saved"
},
navigationOptions: {
tabBarLabel: "Saved",
tabBarOptions: {
activeTintColor: "#00E8AC"
},
tabBarIcon: ({ focused }) => {
return focused ? (
<Icon name="md-heart" type="ionicon" color="#00E8AC" />
) : (
<Icon name="md-heart" type="ionicon" color="#ccc" />
);
}
}
}
});
const MyApp = createStackNavigator(
{
BookingInner: BookingInnerScreen,
Tabs: {
screen: tabNavigator
}
},
{
initialRouteName: "Tabs"
}
);
export default MyApp;
Try this :
const MyApp = createStackNavigator(
{
BookingInner: BookingInnerScreen,
Tabs: {
screen: tabNavigator
}
},
{
initialRouteName: "Tabs",
headerMode: 'none',
}
);
Please help , im not sure how to make this work,
I dont know how to navigate from the login page to the home screen that will contain tabs, i only know how to navigate from the login to the home screen, but without the bottom tabs.
The error i get is: The component for route 'App'must be a React component.
const HomeStack = createStackNavigator(
{
//Defination of Navigaton from home screen
Home: { screen: HomeScreen },
ViewBookings: {
screen: ViewBookingsScreen,
navigationOptions: {
//Header customization of the perticular Screen
headerStyle: {
backgroundColor: '#0892d0',
},
headerTintColor: '#FFFFFF',
title: 'View All Bookings',
//Header title
},
},
},
{
defaultNavigationOptions: {
//Header customization of the perticular Screen
headerStyle: {
backgroundColor: '#0892d0',
},
headerTintColor: '#FFFFFF',
title: 'Welcome, User',
//Header title
},
}
);
const AuthStack = createStackNavigator({ SignIn: SignInScreen });
const App = createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: TabStack,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
);
const TabStack = createBottomTabNavigator(
{
Home : { screen: HomeStack },
Bookings: { screen: BookingStack},
Reminders: { screen: ReminderStack},
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
let IconComponent = Ionicons;
let iconName;
if (routeName === 'Home') {
iconName = `ios-home`;
} else if (routeName === 'Bookings') {
iconName = `ios-book`;
} else if (routeName === 'Reminders') {
iconName = `ios-alarm`;
}
return <IconComponent name={iconName} size={25} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: '#0892d0',
inactiveTintColor: 'gray',
},
}
);
export default createAppContainer(App);
Once you authentication is successful you must call
this.props.navigation.navigate("Home");
This will navigate user to home screen.
You can decide route as per your requirement
In Your Home Screen If you are importing your Login Component like
import {Whatever} from 'Wherever'
Change it to
import Whatever from 'Wherever'
Try by removing curly braces. Because as i see you have used Default with export. So when we used default we dont use braces while importing.
I have a bottom tab bar that locates in app.js. And I have the class where I want to hide the bottom bar. In page home.js I have 2 classes. 1st one is main (is the list of articles), the second one is for button page navigation (in this class I display articles). How I can hide bottom tab navigation in the second page (where articles are displayed). I have tried tabBarVisible: false, but this does not work. Help me, please.
Code:
// app.js
const TabNavigator = createBottomTabNavigator({
Home:{
screen:Home,
navigationOptions:{
tabBarLabel:'Главная',
tabBarIcon:({tintColor})=>(
<Icon name="ios-home" color={tintColor} size={24} />
)
}
},
Courses:{
screen:Courses,
navigationOptions:{
tabBarLabel:'Courses',
tabBarIcon:({tintColor})=>(
<Icon name="ios-school" color={tintColor} size={24} />
)
}
},
Editor:{
screen:Editor,
navigationOptions:{
tabBarLabel:'Editor',
tabBarIcon:({tintColor})=>(
<Icon name="ios-document" color={tintColor} size={24} />
)
}
},
},{
tabBarOptions:{
activeTintColor:'#db0202',
inactiveTintColor:'grey',
style:{
fontSize:3,
height:45,
backgroundColor:'white',
borderTopWidth:0,
elevation: 5
}
}
});
export default createAppContainer(TabNavigator);
// home.js
import React from 'react';
import { Font } from 'expo';
import { Button, View, Text, SafeAreaView, ActivityIndicator, ListView, StyleSheet, Image, Dimensions,
ScrollView } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation'; // Version can be specified in package.json
import Icon from 'react-native-vector-icons/Ionicons'
import Courses from './Courses'
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
};
const { navigate } = this.props.navigation;
return (
<SafeAreaView style={styles.MainContainer}>
<ScrollView
>
<ListView
dataSource={this.state.dataSource}
renderSeparator={this.ListViewItemSeparator}
renderRow={rowData => (
<>
<Text
onPress={() => {
/* 1. Navigate to the Details route with params */
this.props.navigation.navigate("Articles", {
otherParam: rowData.article_title,
});
}}
>
{rowData.article_title}
</Text>
</>
)}
/>
</ScrollView
>
</SafeAreaView>
);
}
}
class ArticleScreen extends React.Component {
static navigationOptions = ({ navigation, navigationOptions }) => {
const { params } = navigation.state;
return {
title: params ? params.otherParam : '',
};
};
render() {
const { params } = this.props.navigation.state;
const article_title = params ? params.otherParam : '';
return (
<Text>{article_title}</Text>
);
}
}
const RootStack = createStackNavigator(
{
Home: {
screen: HomeScreen,
},
Courses: {
screen: Courses,
navigationOptions: {
header: null,
}
},
Articles: {
screen: ArticleScreen,
},
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
You have to make StackNavigator as main Navigator and TabBar as a sub navigator:
const TabBar = createBottomTabNavigator(RouteConfigs, TabNavigatorConfig);
const MainNavigator = createStackNavigator(
{
TabBar,
WelcomeScene: { screen:Scenes.WelcomeScene },
HomeScene: { screen: HomeScene }
}
Using this when you go the second screen Tabbar will hide automatically.
Can you try this?
class ArticleScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: params ? params.otherParam : '',
tabBarVisible: false
};
};
...
How about something like this. Create Tab navigator and pass it down to Stack navigator as one of the screen, when you navigate to the Articles, it will hide the tab bar...
const TabNavigator = createBottomTabNavigator({
Home: {
screen: Home,
navigationOptions: {
tabBarLabel: 'Главная',
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-home" color={tintColor} size={24} />
),
},
},
Courses: {
screen: Courses,
navigationOptions: {
tabBarLabel: 'Courses',
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-school" color={tintColor} size={24} />
),
},
},
Editor: {
screen: Editor,
navigationOptions: {
tabBarLabel: 'Editor',
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-document" color={tintColor} size={24} />
),
},
},
}, {
tabBarOptions: {
activeTintColor: '#db0202',
inactiveTintColor: 'grey',
style: {
fontSize: 3,
height: 45,
backgroundColor: 'white',
borderTopWidth: 0,
elevation: 5,
},
},
});
const stackNavigator = createStackNavigator({
Home: {
screen: TabNavigator,
navigationOptions: {
header: null,
},
},
Articles: {
screen: ArticleScreen,
},
// add screens here which you want to hide the tab bar
});
export default createAppContainer(stackNavigator);
So I'm trying to style the tabNavigator based on the store state:
import React from 'react';
import { connect } from 'react-redux';
import { TabNavigator } from 'react-navigation';
const Tabs = TabNavigator(
// Screens
{
Boards: {
screen: Boards,
navigationOptions: {
tabBarLabel: 'Boards',
tabBarIcon: () => <MaterialCommunityIcon name="bulletin-board" size={25} color="white" />,
},
},
Bookmarks: {
screen: Bookmarks,
navigationOptions: {
tabBarLabel: 'Bookmarks',
tabBarIcon: () => <EntypoIcon name="bookmarks" size={25} color="white" />,
},
},
Settings: {
screen: Settings,
navigationOptions: {
tabBarLabel: 'Settings',
tabBarIcon: () => <MaterialCommunityIcon name="settings" size={25} color="white" />,
},
},
},
// TabNavigator configuration
{
tabBarPosition: 'bottom',
tabBarOptions: {
showIcon: true,
showLabel: false,
renderIndicator: () => null,
style: {
// TODO: Make tabNavigation color change based on current selected theme.
backgroundColor: this.props.theme === 'default' ? 'black' : 'red',
},
},
},
);
const mapStateToProps = state => {
return {
theme: state.configuration.theme,
};
};
export default connect(mapStateToProps)(Tabs);
But when I try to use this.props.theme I get: undefined is not an object (evaluating 'this.props.theme') I guess this happens because tabNavigator doesn't accept props or something like that, so I can't connect tabNavigator to the redux store, so how can I implement what I'm trying to do?
Edit 1
After trying to resolve this using a custom tab bar in the way that was suggested above, this error pops up:
And the code:
TabBar.js
import React from 'react';
import { connect } from 'react-redux';
import { TabBarBottom } from 'react-navigation';
const TabBar = ({ theme }) => (
<TabBarBottom style={{ backgroundColor: theme === 'dark' ? 'black' : 'red' }} />
);
const mapStateToProps = state => ({
theme: state.configuration.theme,
});
export default connect(mapStateToProps)(TabBar);
router.js
import { TabNavigator } from 'react-navigation';
import TabBar from './components/TabBar';
import Boards from './screens/Boards';
import Settings from './screens/Settings';
import Bookmarks from './screens/Bookmarks';
const Tabs = TabNavigator(
// Screens
{
Boards: {
screen: Boards,
navigationOptions: {
tabBarLabel: 'Boards',
tabBarIcon: () => <MaterialCommunityIcon name="bulletin-board" size={25} color="white" />,
},
},
Bookmarks: {
screen: Bookmarks,
navigationOptions: {
tabBarLabel: 'Bookmarks',
tabBarIcon: () => <EntypoIcon name="bookmarks" size={25} color="white" />,
},
},
Settings: {
screen: Settings,
navigationOptions: {
tabBarLabel: 'Settings',
tabBarIcon: () => <MaterialCommunityIcon name="settings" size={25} color="white" />,
},
},
},
// TabNavigator configuration
{
tabBarPosition: 'bottom',
tabBarComponent: TabBar,
},
);
export default Tabs;
You can create your own tab bar, hook it up to the navigator and to redux.
const MyAwesomeTabBar = ({theme}) => (
<View>
...
</View>
)
export default connect(mapStateToProps)(MyAwesomeTabBar);
And then in your navigator definition:
const Tabs = TabNavigator(
// Screens
{
...
},
// TabNavigator configuration
{
tabBarPosition: 'bottom',
tabBarComponent: MyConnectedAwesomeTabBar
},
);
As for the separation of presentational/functional components - I think that it's not so much that not doing it is bad practice, as much as doing it is good practice. And, you can pretty easily separate it here as well, just have MyAwesomeTabBar be your functional component, which uses a bunch of presentational ones.