how to use tabbar in navigator in react-native - react-native

I am now having trouble about this issue.
Because there are some screens which does not use tabbar and also I need to use vector icon in navigationbar, instead of using react-native-tabbar-navigator, I tried to use tabbar in Navigator as below.
render() {
return (
<Navigator
initialRoute={{name: 'LearningList', index: 0}}
renderScene={(route, navigator) =>
{
if (route.name == 'LearningList') {
return (
<LearningList navigator={navigator} />
);
}
if (route.name == 'MyLearning') {
return (
<View style={{ flex: 1, }}>
<MyLearning navigator={navigator} />
<TabBarIOS
tintColor="black"
barTintColor="#3abeff">
<Ionicon.TabBarItemIOS
style={ styles.tabBarItem }
selected={false}
iconName='ios-search'
title='Explorer'
navigator={navigator}
onPress={ this.changeTabSelection('LearningList') }>
<View></View>
</Ionicon.TabBarItemIOS>
<Ionicon.TabBarItemIOS
style={{ backgroundColor: 'green' }}
selected={true}
iconName='ios-list-outline'
title='My Learning'
navigator={navigator}
onPress = { this.changeTabSelection('MyLearning') }>
<View></View>
</Ionicon.TabBarItemIOS>
</TabBarIOS>
</View>
);
}
if (route.name == 'Schedule') {
return (
<Schedule navigator={navigator} learningID={ route.learningID } />
);
}
}
}
/>
);
}
But when I click TabBarItemIOS buttons, onPress event does not invoked at all, and if I click edit button in LearningList page, the onPress callbacks are invoked for all TabBarItemIOS buttons.
Here is LearningList.js next button content.
const rightButtonConfig = {
title: 'Next >',
handler: () => {
this.props.navigator.push({
name: 'MyLearning'
});
}
};
So, I hope to know the right way of using tabbar in Navigator.
Please help me!!!

It is because you are calling that function instead of passing a function reference. To do what you want, you simply need arrow functions. For example replace:
onPress={ this.changeTabSelection('LearningList') }>
to
onPress={ () => this.changeTabSelection('LearningList') }>

Related

ScrollToIndex in React-Native

In my application, I want to use scrollToIndex() which is a method of the FlatList component.
render() {
let { posts, featuredWorkouts, mainFeedIsLoading } = this.props;
let mainFeed = <SwiperContainer featuredWorkouts={featuredWorkouts} />;
let mainFeedData = (
<View>
<View style={{ marginBottom: 5 }}>
<SwiperContainer featuredWorkouts={featuredWorkouts} />
</View>
<FlatList
data={posts}
scrollToIndex={5}
extraData={[posts, mainFeedIsLoading]}
renderItem={item => this.renderPost(item)}
keyExtractor={item => item.shareId}
/>
</View>
);
if (mainFeedIsLoading) {
mainFeedData = (
<View style={styles.screenLoader}>
<ScreenLoader color="lightblue" size="large" />
</View>
);
}
return (
<View>
<ScrollView>{mainFeedData}</ScrollView>
</View>
);
}
As an example, when the page loads, I want to go to the 10th index. How can I achieve this? I tried the scrollToIndex() and it did not work.
you have to add ref to your flat list.
ref={(ref) => { this.list = ref; }}
Also you have to add to scroll index to your componentdidmount.
componentDidMount() {
this.list.scrollToIndex({animated: true, index: tempIndex, viewOffset:0,viewPosition:0});
}
Also you can use:
initialScrollIndex
Well in my case I have to do this to make scrolltoindex work properly,
1.add reference to flatlist:
`
ref={ref => {
this.flatListRef = ref;
}}
`
2. Call scrollToIndex() with timeout:
`
setTimeout(() => {
this.flatListRef.scrollToIndex({
animated: true,
index: this.state.pressedIndex
});
}, 500);
`
3. then call function again inside flatlist
onScrollToIndexFailed={() =>
{
this.scrollToIndex();
}
}

Handle Multiselect in a GridView

I'm trying to handle the multi-select with react-native-super-grid , here is my code :
<GridView
itemDimension={80}
items={items}
style={styles.gridView}
renderItem={item => (
<View style={[styles.itemContainer , { backgroundColor:' transparent '}]}>
<TouchableHighlight style={styles.buttonStyle} onPress={() => this.pressEvent() }>
<Text> {item.image}</Text>
</TouchableHighlight>
<Text style={styles.buttonText}> {item.name}</Text>
</View>)}
/>
I tried using this function :
pressEvent(arr){
if(this.state.pressStatus == false){
this.setState({ pressStatus: true})
this.state.arr.push(arr)
this.setState({ color : 'white'})
} else {
this.setState({ pressStatus: false})
this.setState({ color: 'red'})
}
}
but it somehow doesn't work , can someone help me ?
Thank you .
This short example should give you an idea what are you doing wrong. The items itself are not aware of the state. So what I would do, I would create a separate child component for grid item and handle press state locally. Then handle parent, which is holding all the item trough callback about the pressed item.
class MyGridView extends Component {
render() {
return (
<GridView
itemDimension={80}
items={items}
style={styles.gridView}
renderItem={item => (
<GridItem
item={item}
onItemPress={selected => {
// set grid view callback
if (selected) {
//if true add to array
this.addToPressedArray(item);
} else {
//false remove from array
this.removeFromPressedArray(item);
}
}}
/>
)}
/>
);
}
// You don't change the state directly, you mutate it trough set state
addToPressedArray = item => this.setState(prevState => ({ arr: [...prevState.arr, item] }));
removeFromPressedArray = item => {
const arr = this.state.arr.remove(item);
this.setState({ arr });
};
}
And the GridItem
class GridItem extends Component {
// starting local state
state = {
pressStatus: false,
color: 'red'
};
// handle on item press
pressEvent = () => {
this.setState(prevState => ({
pressStatus: !prevState.pressStatus, //negate previous on state value
color: !prevState.pressStatus ? 'white' : 'red' //choose corect collor based on pressedStatus
}));
// call parent callback to notify grid view of item select/deselect
this.props.onItemPress(this.state.pressStatus);
};
render() {
return (
<View style={[styles.itemContainer, { backgroundColor: ' transparent ' }]}>
<TouchableHighlight style={styles.buttonStyle} onPress={() => this.pressEvent()}>
<Text> {item.image}</Text>
</TouchableHighlight>
<Text style={styles.buttonText}> {item.name}</Text>
</View>
);
}
}
I also recommend to read about React.Component lifecycle. Its a good reading and gives you a better understanding how to achieve updates.
Since GridView has been merged into FlatGrid. Therefore, I've implemented the multi-select option in a pretty easy way. First of all I applied TouchableOpacity on top of the view in the renderItems prop of FlatGrid like this.
<TouchableOpacity
onPress={() => this.selectedServices(item.name)}>
...props
</TouchableOpacity>
SelectedServices:
selectedServices = item => {
let services = this.state.selectedServices;
if (services.includes(item) == false) {
services.push(item);
this.setState({ selectedServices: services });
} else {
let itemIndex = services.indexOf(item);
services.splice(itemIndex, 1);
this.setState({ selectedServices: services });
}
};
Using splice, indexOf, and push, you can easily implement multi-selection.
To change the backgroundColor of the currently selected item, you can apply a check on the backgroundColor prop of the view.
renderItem={({ item, index }) => (
<TouchableOpacity
onPress={() => this.selectedServices(item.name)}
>
<View
style={[
styles.itemContainer,
{
backgroundColor: this.state.selectedServices.includes(
item.name
)
? '#0052cc'
: item.code
}
]}
>
<Text style={styles.itemName}>{item.name}</Text>
</View>
</TouchableOpacity>
)}

How to relate react native ToolbarAndroid with Navigator

I would like to know a way to relate ToolbarAndroid with the Navigator component. My intention is always to show the route.title in a ToolbarAndroid child, such as a Text component. This way, if a use the BackAndroid component, my title is always up to date! I don't want to use Navigator.NavigationBar because I would miss the overflow menu built in on the ToolbarAndroid.
Appreciate any help.
Here is my code:
//... some code before
render() {
return(
<DrawerLayoutAndroid
drawerWidth={300}
ref={(drawerElement) => { this.DRAWER = drawerElement; }}
drawerPosition={DrawerLayoutAndroid.positions.left}
onDrawerOpen={this.setDrawerState}
onDrawerClose={this.setDrawerState}
renderNavigationView={() => <DrawerMenu navigate={this.navigateTo} />}
>
<Icon.ToolbarAndroid
titleColor='#fff'
navIconName='md-menu'
onIconClicked={this.toggleDrawer}
actions={toolbarActions}
onActionSelected={this._onActionSelected}
style={styles.appBar}
overflowIconName="md-more"
>
<View>
<TouchableOpacity
onPress={this.navigateTo.bind(this, 0)}
style={styles.appBarLogo}
>
<Icon name="md-boat" size={30} color="#fff" />
<Text
style={styles.appBarTitle}
numberOfLines={1}
>
{this.state.title}
</Text>
</TouchableOpacity>
</View>
</Icon.ToolbarAndroid>
<Navigator
initialRoute={routes[0]}
renderScene={(route, navigator) => {
switch (route.index) {
case 0:
return <Home />
case 1:
return <Lindau />;
case 2:
return <About />;
case 3:
return <Credits />;
default:
return <Home />;
}
}}
configureScene={(route, routeStack) =>
Navigator.SceneConfigs.FloatFromRight
}
ref={(nav) => { this._navigator = nav; }}
/>
</DrawerLayoutAndroid>
);
}
So, please, help me if anyone has a better solution for this. After several attempts, I figured out one possible solution.
I created a state for my component called 'routes', then, I've set up my Toolbar title with this state. Basically, this state is a stack of my routes. When I change my scene, I push this route in my state, when I back from BackAndroid component, I pop out the route from the state, and everything works fine.
Here the code fixed:
class App extends Component {
constructor(props) {
super(props);
this.state = {
routes: [0], // Here the state to fix the problem...
drawerClosed: true,
}
this.toggleDrawer = this.toggleDrawer.bind(this);
this._onActionSelected = this._onActionSelected.bind(this);
this.navigateTo = this.navigateTo.bind(this);
this.setDrawerState = this.setDrawerState.bind(this);
this.handlesBackButton = this.handlesBackButton.bind(this);
}
navigateTo(idx) {
this.setState({
routes: [ ...this.state.routes, idx]
});
this.DRAWER.closeDrawer();
if (idx === 0) {
this._navigator.resetTo(routes[0]);
this.setState({
routes: [0]
});
} else {
this._navigator.push(routes[idx]);
}
}
handlesBackButton() {
if (this._navigator && this._navigator.getCurrentRoutes().length > 1) {
try {
this._navigator.jumpBack();
const _routes = this.state.routes.slice();
_routes.pop();
this.setState({
routes: _routes
});
} catch(e) {}
return true;
}
return false;
}
render() {
return(
<DrawerLayoutAndroid
drawerWidth={300}
ref={(drawerElement) => { this.DRAWER = drawerElement; }}
drawerPosition={DrawerLayoutAndroid.positions.left}
onDrawerOpen={this.setDrawerState}
onDrawerClose={this.setDrawerState}
renderNavigationView={() => <DrawerMenu navigate={this.navigateTo} />}
>
<Icon.ToolbarAndroid
titleColor='#fff'
navIconName='md-menu'
onIconClicked={this.toggleDrawer}
actions={toolbarActions}
onActionSelected={this._onActionSelected}
style={styles.appBar}
overflowIconName="md-more"
>
<View style={styles.appBarLogo}> // I have to fix this component view...
<TouchableOpacity
onPress={this.navigateTo.bind(this, 0)}
>
<Icon name="md-boat" size={30} color="#fff" />
</TouchableOpacity>
<Text
style={styles.appBarTitle}
numberOfLines={1}
>
{routes[this.state.routes[this.state.routes.length - 1]].title}
</Text>
</View>
</Icon.ToolbarAndroid>
<Navigator
initialRoute={routes[0]}
renderScene={(route, navigator) => {
switch (route.index) {
case 0:
return <Home />;
case 1:
return <Lindau />;
case 2:
return <About />;
case 3:
return <Credits />;
default:
return <Home />;
}
}}
configureScene={(route, routeStack) =>
Navigator.SceneConfigs.FloatFromRight
}
ref={(nav) => { this._navigator = nav; }}
/>
</DrawerLayoutAndroid>
);
}
}

React Native - How to re-render Navigator component on icon press

How would I re-render/ change the colour of a Navigator component icon when it is pressed. I have TouchableHighlight on it but I need the state to stay permanently. For example someone presses a 'favourite' heart icon, and it turns from grey to red. I've been trying to figure out a solution for some time now.
This is the section of my code where the change should happen. I need my if statement and Navigator icon to re-render based on the true/false value which changes when the TouchableHighlight onPress triggers.
var NavigationBarRouteMapper = {
RightButton: function(route, navigator, index, navState) {
// * The button displayed in the top right of the navigator
switch(route.id) {
case('businessProfile'):
if (route.isFavourited) {
return (
<View style={[ styles.multipleIcons ]}>
<TouchableOpacity
onPress={() => {
var favouriteBusiness = new FavouriteBusiness();
favouriteBusiness.updateBusinessAsFavourite(route.business.id)
}}
style={[ styles.navBarButton, styles.iconRightPaddingLarge ]}
>
<IconFA
name='heart'
size={ 25 }
color='#de6262'
style={ styles.icon }
/>
</TouchableOpacity>
</View>
);
} else {
return (
<View style={[ styles.multipleIcons ]}>
<TouchableOpacity
onPress={() => {
var favouriteBusiness = new FavouriteBusiness();
favouriteBusiness.updateBusinessAsFavourite(route.business.id)
}}
style={[ styles.navBarButton, styles.iconRightPaddingLarge ]}
>
<IconFA
name='heart'
size={ 25 }
color='#ddd'
style={ styles.icon }
/>
</TouchableOpacity>
</View>
);
}
default:
return null;
}
},
};
<Navigator
ref='navigator'
sceneStyle={ [styles.container, styles.inner] }
initialRoute={{
id: this.props.scene,
title:this.props.title
}}
renderScene={ this.renderScene }
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.FloatFromRight;
}}
navigationBar={
<Navigator.NavigationBar
routeMapper={ NavigationBarRouteMapper }
style={ styles.navigationBar }
/>
}
/>
if you still did not get the solution perhaps these could help.
you can define some Properties in construktor:
constructor(props) {
super(props);
this.state = {
color: 'lightgrey',
};
}
You can define the Icon in the RooteMapper of the Navigaton bar:
return (<Icon
name="star"
style={[styles.rightHadderButton, {color: this.state.color}]}
onPress={RightNavigatorButton.favoriteStar.bind(this)}/>);
and then change the collor in the onpress defined Function:
exports.favoriteStar = function(event) {
if (this.state.color === 'lightgrey') {
this.setState({ color: '#990000' });
AlertIOS.alert( "favoriteStar","Favorite");
} else {
this.setState({ color: 'lightgrey' });
AlertIOS.alert( "favoriteStar","notFavorite");
}
}
Hope these works for you too and it helps you.

how to show navigation bar using navigator component in react-native

Hi every one I am trying to use navigator component in place of navigatorIOS, but what the problem navigator is not showing in view, below is my code for navigator and navigatorIOS
NavigatorIOS:
<NavigatorIOS
style={styles.navigator}
barTintColor='#37475e'
titleTextColor='white'
initialRoute={{
title:' Words',
component:Main
}}/>
using navigatorIOS I can view the navbar but using using navigator Component I am facing problem I want to use navigator component instead of navigatorIOS
Navigator Component:
<Navigator
style={styles.navigator}
TintColor='#37475e'
titleTextColor='white'
initialRoute={{
title:'Words',
component:Main
}}
renderScene={(route, navigator) =>{
return <route.component navigator={navigator} {...route.passProps} />;
}}/>
Can any one give me suggestions for how to solve this any help much appreciated
Yes, you need to create a <Navigator.NavigationBar />, and pass it in as a prop to the Navigator:
class App extends React.Component {
render() {
return (
<Navigator
style={{flex:1}}
initialRoute={{name: 'Main', component: Main, index: 0}}
renderScene={(route, navigator) => {
if (route.component) {
return React.createElement(route.component, { ...this.props, ...route.passProps, navigator, route } );
}
}}
navigationBar={ <Navigator.NavigationBar routeMapper={NavigationBarRouteMapper} /> }
/>
)
}
}
You then need to create a routeMapper object, which you pass in as a prop to the Navigator.NavigationBar:
var NavigationBarRouteMapper = {
LeftButton(route, navigator, index, navState) {
if(index > 0) {
return (
<TouchableHighlight style={{marginTop: 10}} onPress={() => {
if (index > 0) {
navigator.pop();
}
}}>
<Text>Back</Text>
</TouchableHighlight>
)} else {
return null}
},
RightButton(route, navigator, index, navState) {
return null;
},
Title(route, navigator, index, navState) {
return <Text>Hello From My App!</Text>
}
};
There is a great example in the UI Explorer in their GitHub, check it out here.
App.js
<Navigator
ref={(ref) => this._navigator = ref}
configureScene={(route) => Navigator.SceneConfigs.FloatFromLeft}
initialRoute={{
id: 'Main',
title: 'Words'
}}
renderScene={(route, navigator) => this._renderScene(route, navigator)}
navigationBar={
<Navigator.NavigationBar
style={styles.navBar}
routeMapper={NavigationBarRouteMapper} />
}
/>
This code for left, right and title on navigationBar in react-native
const NavigationBarRouteMapper = {
LeftButton(route, navigator, index, navState) {
switch (route.id) {
case 'Page1':
case 'Page2':
case 'Page3':
return (
<TouchableOpacity
style={styles.navBarLeftButton}
onPress={() => {_emitter.emit('openMenu')}}>
<Icon name='menu' size={25} color={'white'} />
</TouchableOpacity>
)
default:
return null
}
},
RightButton(route, navigator, index, navState) {
switch (route.id) {
case 'Page1':
return (
<TouchableOpacity
style={styles.navBarRightButton} onPress={() => {route.onPress()}}>
<Icon name={'map'} size={25} color={'white'} />
</TouchableOpacity>
)
case 'Page2':
return (
<TouchableOpacity
style={styles.navBarRightButton} onPress={() => {route.onPress()}}>
<Icon name={'map'} size={25} color={'white'} />
</TouchableOpacity>
)
case 'Page3':
return (
<TouchableOpacity
style={styles.navBarRightButton} onPress={() => {route.onPress()}}>
<Icon name={'tab'} size={25} color={'white'} />
</TouchableOpacity>
)
default:
return null
}
},
Title(route, navigator, index, navState) {
return (
<Text style={[styles.navBarText, styles.navBarTitleText]}>
{route.title}
</Text>
)
}
}
route.onPress(): method to call right button click.
route.title: set title of page.
For reference, use following link: Navigator