J'ai trouvé peu de publications qui donnent des "astuces" sur la façon d'intégrer navigation\routes avec le menu latéral de react-native-native. Malheureusement, aucune publication ne montre un exemple complet de cette fonctionnalité.
Je ne sais pas non plus quelle est la mise en oeuvre la plus simple pour la navigation\routes, et quelle est la différence entre ces 2 options (bien sûr, cela ne concerne pas spécifiquement le menu latéral, mais dans mon cas, il devrait être fusionné).
Quelqu'un peut-il indiquer un tel exemple?
J'ai donc finalement réussi à intégrer le navigateur standard, comme le montre l'exemple de code officiel de Facebook:
https://github.com/facebook/react-native/tree/master/Examples/UIExplorer/Navigator
Avec le composant react-native-side-menu, voici comment tout le code se présente:
'use strict';
var React = require('react');
var ReactNative = require('react-native');
var SideMenu = require('react-native-side-menu');
var {
Component,
Navigator,
AppRegistry,
View,
Text,
Image,
StyleSheet,
ScrollView,
TouchableOpacity
} = ReactNative;
class FirstPage extends Component {
render() {
return (
<View style={styles.page}><Text style={styles.pageContent}>First Page</Text></View>
);
}
}
class FirstPageMenu extends Component {
constructor(props) {
super(props);
this.state = {};
}
toggle() {
this.setState({
isOpen: !this.state.isOpen,
});
}
updateMenuState(isOpen) {
this.setState({ isOpen, });
}
onMenuItemSelected = (item) => {
this.setState({
isOpen: false,
selectedItem: item,
});
this.props.navigator.replace({ id: item });
}
render() {
const menu = <Menu onItemSelected={this.onMenuItemSelected} navigator={this.props.navigator}/>;
return (
<SideMenu
menu={menu}
isOpen={this.state.isOpen}
onChange={(isOpen) => this.updateMenuState(isOpen)}>
<MenuButton onPress={() => this.toggle()}/>
<FirstPage/>
</SideMenu>
);
}
};
class SecondPage extends Component {
...
}
class SecondPageMenu extends Component {
...
}
class ThirdPage extends Component {
...
}
class ThirdPageMenu extends Component {
...
}
class MenuNavigator extends Component {
constructor(props) {
super(props);
this._setNavigatorRef = this._setNavigatorRef.bind(this);
}
renderScene(route, nav) {
switch (route.id) {
case 'first':
return <FirstPageMenu navigator={nav} />;
case 'second':
return <SecondPageMenu navigator={nav} />;
case 'third':
return <ThirdPageMenu navigator={nav} />;
default:
return <FirstPageMenu navigator={nav} />;
}
}
render() {
return (
<Navigator
ref={this._setNavigatorRef}
initialRoute={{id: 'first'}}
renderScene={this.renderScene}
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.FloatFromBottom;
}}
/>
);
}
componentWillUnmount() {
this._listeners && this._listeners.forEach(listener => listener.remove());
}
_setNavigatorRef(navigator) {
if (navigator !== this._navigator) {
this._navigator = navigator;
if (navigator) {
var callback = (event) => {
console.log(
`NavigatorMenu: event ${event.type}`,
{
route: JSON.stringify(event.data.route),
target: event.target,
type: event.type,
}
);
};
// Observe focus change events from the owner.
this._listeners = [
navigator.navigationContext.addListener('willfocus', callback),
navigator.navigationContext.addListener('didfocus', callback),
];
}
}
}
};
class MenuButton extends Component {
handlePress(e) {
if (this.props.onPress) {
this.props.onPress(e);
}
}
render() {
return (
<View style={styles.menuButton} >
<TouchableOpacity
onPress={this.handlePress.bind(this)}
style={this.props.style}>
<Text>{this.props.children}</Text>
<Image
source={{ uri: 'http://i.imgur.com/vKRaKDX.png', width: 40, height: 40, }} />
</TouchableOpacity>
</View>
);
}
}
class Menu extends Component {
static propTypes = {
onItemSelected: React.PropTypes.func.isRequired,
};
constructor(props) {
super(props);
}
render() {
return (
<ScrollView scrollsToTop={false} style={styles.menu}>
<Text
onPress={() => this.props.onItemSelected('first')}
style={styles.item}>
First
</Text>
<Text
onPress={() => this.props.onItemSelected('second')}
style={styles.item}>
Second
</Text>
<Text
onPress={() => this.props.onItemSelected('third')}
style={styles.item}>
Third
</Text>
</ScrollView>
);
}
};
var styles = StyleSheet.create({
menuButton: {
marginTop: 20,
backgroundColor: '#777'
},
menu: {
flex: 1,
width: window.width,
height: window.height,
padding: 20,
},
item: {
fontSize: 16,
fontWeight: '300',
paddingTop: 20,
},
page: {
flex: 1,
alignItems: 'center',
backgroundColor: '#777'
},
pageContent: {
flex: 1,
alignItems: 'center',
top: 200,
},
menu: {
flex: 1,
width: window.width,
height: window.height,
padding: 20,
},
item: {
fontSize: 16,
fontWeight: '300',
paddingTop: 20,
},
});
module.exports = MenuNavigator;
Et le fichier d'index devrait juste pointer sur Navigator:
const React = require('react-native');
const { AppRegistry, } = React;
const MenuNavigator = require('./SideMenuWithNavigation');
AppRegistry.registerComponent('MyApp', () => MenuNavigator);
Si vous voulez parler du menu des tiroirs, cochez react-native-material-design et l'application de démonstration donnée.
react-native-side-menu
et navigator
.Ce démarreur utilise également redux (n'empêchera pas de répondre à la question de savoir comment traiter le navigateur + le menu latéral).
Lors de l'utilisation de sidemenu, la trick
pour routing
consiste à remplacer la route précédente pour l'empêcher d'empiler (comme il se doit dans une navigation commune):
navigate(route) {
const routeStack = [].concat(this.refs.navigator.getCurrentRoutes());
const previousRouteId = routeStack[routeStack.length - 1].id;
if (route.id !== previousRouteId) {
this.refs.navigator.replace(route);
}
if (this.state.sideMenuOpened) {
this.closeSideMenu();
}
}
Vérifiez mon démarreur reactNativeReduxFastStarter
aperçu rapide du code:
import React, {
Component
} from 'react';
import {
StyleSheet,
Text,
Dimensions,
Navigator,
StatusBar
} from 'react-native';
import SideMenu from 'react-native-side-menu';
import Icon from 'react-native-vector-icons/Ionicons';
import { AppRoutes } from '../../../common/config';
import {
SideMenuContent,
Button
} from '../../components';
import Home from '../home';
import AppState from '../appState';
const SCREEN_WIDTH = Dimensions.get('window').width;
class App extends Component {
constructor(props) {
super(props);
this.init();
}
init() {
this.state = {
sideMenuOpened: false
};
}
openSideMenu() {
this.setState({
sideMenuOpened : false
});
}
closeSideMenu() {
if (this.state.sideMenuOpened) {
this.setState({
sideMenuOpened : false
});
}
}
toggleSideMenu() {
this.setState({
sideMenuOpened: !this.state.sideMenuOpened
});
}
updateSideMenuState(isOpened) {
this.setState({
sideMenuOpened: isOpened
});
}
navigate(route) {
const routeStack = [].concat(this.refs.navigator.getCurrentRoutes());
const previousRouteId = routeStack[routeStack.length - 1].id;
if (route.id !== previousRouteId) {
this.refs.navigator.replace(route);
}
if (this.state.sideMenuOpened) {
this.closeSideMenu();
}
}
renderScene(route, navigator) {
switch (route.id) {
case 1:
const route1 = AppRoutes.getRouteFromRouteId(1);
return (
<Home
ref={route1.refView}
navigator={navigator}
navigate={(toRoute)=>this.navigate(toRoute)}
/>
);
case 2:
const route2 = AppRoutes.getRouteFromRouteId(2);
return (
<AppState
ref={route2.refView}
navigator={navigator}
navigate={(toRoute)=>this.navigate(toRoute)}
/>
);
default:
return (
<Home
ref={route1.refView}
navigator={navigator}
navigate={(toRoute)=>this.navigate(toRoute)}
/>
);
}
}
renderRouteMapper() {
const routes = AppRoutes.getAllRoutes();
return {
Title : (route, navigator, index, navState) => {
const currentRouteId = navState.routeStack[index].id;
return (
<Text style={styles.titleNavText}>
{routes[currentRouteId - 1].navbar.navBarTitle}
</Text>
);
},
LeftButton : (route, navigator, index, navState) => {
const currentRouteId = navState.routeStack[index].id;
return (
<Button
style={styles.leftNavButton}
onPress={(e)=>this.toggleSideMenu(e)
}>
<Icon
name={routes[currentRouteId - 1].navbar.navBarLeftIconName}
size={32}
color={'#333333'}
/>
</Button>
);
},
RightButton : (route, navigator, index, navState) => {
return null;
}
};
}
render() {
StatusBar.setBarStyle('light-content', true);
const DEFAULT_ROUTE = { id: 1, refView: 'HomeView' };
return (
<SideMenu
menu={<SideMenuContent
backGndColor="#ECECEC"
navigate={(route)=>this.navigate(route)}
/>}
isOpen={this.state.sideMenuOpened}
onChange={(isOpened) => this.updateSideMenuState(isOpened)}
bounceBackOnOverdraw={false}
openMenuOffset={SCREEN_WIDTH * 0.8}
>
<Navigator
ref="navigator"
initialRoute={ DEFAULT_ROUTE }
sceneStyle={ styles.navigator }
renderScene={(route, navigator)=>this.renderScene(route, navigator)}
configureScene={()=>Navigator.SceneConfigs.FadeAndroid}
navigationBar={
<Navigator.NavigationBar
routeMapper={this.renderRouteMapper()}
style={styles.navBar}
/>
}
/>
</SideMenu>
);
}
}
const styles = StyleSheet.create({
navigator: {
backgroundColor: '#fff',
borderLeftWidth: 0.5,
borderLeftColor: '#F1F1F1',
},
navBar: {
backgroundColor: '#fff',
borderWidth: 0.5,
borderColor: '#F1F1F1'
},
leftNavButton : {
flex : 1,
flexDirection : 'column',
alignItems : 'center',
marginTop : 4,
paddingTop : 0,
paddingBottom : 10,
paddingLeft : 20,
paddingRight : 10
},
rightNavButton : {
flex : 1,
flexDirection : 'column',
alignItems : 'center',
marginTop : 4,
paddingTop : 6,
paddingBottom : 10,
paddingLeft : 10,
paddingRight : 10
},
titleNavText : {
marginTop : 14,
color : '#333333'
}
});
export default App;
Vous pouvez vérifier ce projet complet sidemenu sur github. Ce projet contient ToolbarAndroid, routes, DrawerLayoutAndroid, un menu déroulant et d’autres composants.