NavigatorIOS is a wrapper around UINavigationController, enabling you to implement a navigation stack. It works exactly the same as it would on a native app using UINavigationController, providing the same animations and behavior from UIKIt.

As the name implies, it is only available on iOS. Take a look at Navigator for a similar solution for your cross-platform needs, or check out react-native-navigation, a component that aims to provide native navigation on both iOS and Android.

To set up the navigator, provide the initialRoute prop with a route object. A route object is used to describe each scene that your app navigates to. initialRoute represents the first route in your navigator.

import React, { Component, PropTypes } from 'react';
import { NavigatorIOS, Text } from 'react-native';

export default class NavigatorIOSApp extends Component {
  render() {
    return (
      <NavigatorIOS
        initialRoute={{
          component: MyScene,
          title: 'My Initial Scene',
        }}
        style={{flex: 1}}
      />
    );
  }
}

class MyScene extends Component {
  static propTypes = {
    title: PropTypes.string.isRequired,
    navigator: PropTypes.object.isRequired,
  }

  constructor(props, context) {
    super(props, context);
    this._onForward = this._onForward.bind(this);
    this._onBack = this._onBack.bind(this);
  }

  _onForward() {
    this.props.navigator.push({
      title: 'Scene ' + nextIndex,
    });
  }

  render() {
    return (
      <View>
        <Text>Current Scene: { this.props.title }</Text>
        <TouchableHighlight onPress={this._onForward}>
          <Text>Tap me to load the next scene</Text>
        </TouchableHighlight>
      </View>
    )
  }
}

In this code, the navigator renders the component specified in initialRoute, which in this case is MyScene. This component will receive a route prop and a navigator prop representing the navigator. The navigator's navigation bar will render the title for the current scene, "My Initial Scene".

You can optionally pass in a passProps property to your initialRoute. NavigatorIOS passes this in as props to the rendered component:

initialRoute={{
  component: MyScene,
  title: 'My Initial Scene',
  passProps: { myProp: 'foo' }
}}

You can then access the props passed in via {this.props.myProp}.

处理导航

To trigger navigation functionality such as pushing or popping a view, you have access to a navigator object. The object is passed in as a prop to any component that is rendered by NavigatorIOS. You can then call the relevant methods to perform the navigation action you need:

class MyView extends Component {
  _handleBackPress() {
    this.props.navigator.pop();
  }

  _handleNextPress(nextRoute) {
    this.props.navigator.push(nextRoute);
  }

  render() {
    const nextRoute = {
      component: MyView,
      title: 'Bar That',
      passProps: { myProp: 'bar' }
    };
    return(
      <TouchableHighlight onPress={() => this._handleNextPress(nextRoute)}>
        <Text style={{marginTop: 200, alignSelf: 'center'}}>
          See you on the other nav {this.props.myProp}!
        </Text>
      </TouchableHighlight>
    );
  }
}
You can also trigger navigator functionality from the NavigatorIOS component:

class NavvyIOS extends Component {
  _handleNavigationRequest() {
    this.refs.nav.push({
      component: MyView,
      title: 'Genius',
      passProps: { myProp: 'genius' },
    });
  }

  render() {
    return (
      <NavigatorIOS
        ref='nav'
        initialRoute={{
          component: MyView,
          title: 'Foo This',
          passProps: { myProp: 'foo' },
          rightButtonTitle: 'Add',
          onRightButtonPress: () => this._handleNavigationRequest(),
        }}
        style={{flex: 1}}
      />
    );
  }
}

The code above adds a _handleNavigationRequest private method that is invoked from the NavigatorIOS component when the right navigation bar item is pressed. To get access to the navigator functionality, a reference to it is saved in the ref prop and later referenced to push a new scene into the navigation stack.

导航栏的配置

Props passed to NavigatorIOS will set the default configuration for the navigation bar. Props passed as properties to a route object will set the configuration for that route's navigation bar, overriding any props passed to the NavigatorIOScomponent.

_handleNavigationRequest() {
  this.refs.nav.push({
    //...
    passProps: { myProp: 'genius' },
    barTintColor: '#996699',
  });
}

render() {
  return (
    <NavigatorIOS
      //...
      style={{flex: 1}}
      barTintColor='#ffffcc'
    />
  );
}

In the example above the navigation bar color is changed when the new route is pushed.

截图

属性

barTintColor string #

导航条的背景颜色。

initialRoute {component: function, title: string, passProps: object, backButtonIcon: Image.propTypes.source, backButtonTitle: string, leftButtonIcon: Image.propTypes.source, leftButtonTitle: string, onLeftButtonPress: function, rightButtonIcon: Image.propTypes.source, rightButtonTitle: string, onRightButtonPress: function, wrapperStyle: [object Object]} #

NavigatorIOS使用"路由"对象来包含要渲染的子视图、它们的属性、以及导航条配置。"push"和任何其它的导航函数的参数都是这样的路由对象。

itemWrapperStyle View#style #

导航器中的组件的默认属性。一个常见的用途是设置所有页面的背景颜色。

navigationBarHidden bool #

一个布尔值,决定导航栏是否隐藏。

shadowHidden bool #

一个布尔值,决定是否要隐藏1像素的阴影

tintColor string #

导航栏上按钮的颜色。

titleTextColor string #

导航器标题的文字颜色。

translucent bool #

一个布尔值,决定是否导航条是半透明的。

interactivePopGestureEnabled bool #

决定是否启用滑动返回手势。不指定此属性时,手势会根据navigationBar的显隐情况决定是否启用(显示时启用手势,隐藏时禁用手势)。指定此属性后,手势与navigationBar的显隐情况无关。

方法

push(route: { component: Function; title: string; passProps?: Object; backButtonTitle?: string; backButtonIcon?: Object; leftButtonTitle?: string; leftButtonIcon?: Object; onLeftButtonPress?: Function; rightButtonTitle?: string; rightButtonIcon?: Object; onRightButtonPress?: Function; wrapperStyle?: any; }) #

Navigate forward to a new route

popN(n: number) #

Go back N pages at once. When N=1, behavior matches pop()

pop() #

Go back one page

replaceAtIndex(route: { component: Function; title: string; passProps?: Object; backButtonTitle?: string; backButtonIcon?: Object; leftButtonTitle?: string; leftButtonIcon?: Object; onLeftButtonPress?: Function; rightButtonTitle?: string; rightButtonIcon?: Object; onRightButtonPress?: Function; wrapperStyle?: any; }, index: number) #

Replace a route in the navigation stack.

index specifies the route in the stack that should be replaced. If it's negative, it counts from the back.

replace(route: { component: Function; title: string; passProps?: Object; backButtonTitle?: string; backButtonIcon?: Object; leftButtonTitle?: string; leftButtonIcon?: Object; onLeftButtonPress?: Function; rightButtonTitle?: string; rightButtonIcon?: Object; onRightButtonPress?: Function; wrapperStyle?: any; }) #

Replace the route for the current page and immediately load the view for the new route.

replacePrevious(route: { component: Function; title: string; passProps?: Object; backButtonTitle?: string; backButtonIcon?: Object; leftButtonTitle?: string; leftButtonIcon?: Object; onLeftButtonPress?: Function; rightButtonTitle?: string; rightButtonIcon?: Object; onRightButtonPress?: Function; wrapperStyle?: any; }) #

Replace the route/view for the previous page.

popToTop() #

Go back to the top item

popToRoute(route: { component: Function; title: string; passProps?: Object; backButtonTitle?: string; backButtonIcon?: Object; leftButtonTitle?: string; leftButtonIcon?: Object; onLeftButtonPress?: Function; rightButtonTitle?: string; rightButtonIcon?: Object; onRightButtonPress?: Function; wrapperStyle?: any; }) #

Go back to the item for a particular route object

replacePreviousAndPop(route: { component: Function; title: string; passProps?: Object; backButtonTitle?: string; backButtonIcon?: Object; leftButtonTitle?: string; leftButtonIcon?: Object; onLeftButtonPress?: Function; rightButtonTitle?: string; rightButtonIcon?: Object; onRightButtonPress?: Function; wrapperStyle?: any; }) #

Replaces the previous route/view and transitions back to it.

resetTo(route: { component: Function; title: string; passProps?: Object; backButtonTitle?: string; backButtonIcon?: Object; leftButtonTitle?: string; leftButtonIcon?: Object; onLeftButtonPress?: Function; rightButtonTitle?: string; rightButtonIcon?: Object; onRightButtonPress?: Function; wrapperStyle?: any; }) #

Replaces the top item and popToTop

例子

'use strict';

const React = require('react');
const ReactNative = require('react-native');
const ViewExample = require('./ViewExample');

const createExamplePage = require('./createExamplePage');
const nativeImageSource = require('nativeImageSource');
const {
  AlertIOS,
  NavigatorIOS,
  ScrollView,
  StyleSheet,
  Text,
  TouchableHighlight,
  View,
} = ReactNative;

class EmptyPage extends React.Component {
  render() {
    return (
      <View style={styles.emptyPage}>
        <Text style={styles.emptyPageText}>
          {this.props.text}
        </Text>
      </View>
    );
  }
}

class NavigatorIOSExamplePage extends React.Component {
  render() {
    var recurseTitle = 'Recurse Navigation';
    if (!this.props.depth || this.props.depth === 1) {
      recurseTitle += ' - more examples here';
    }
    return (
      <ScrollView style={styles.list}>
        <View style={styles.line}/>
        <View style={styles.group}>
          {this._renderRow(recurseTitle, () => {
            this.props.navigator.push({
              title: NavigatorIOSExample.title,
              component: NavigatorIOSExamplePage,
              backButtonTitle: 'Custom Back',
              passProps: {depth: this.props.depth ? this.props.depth + 1 : 1},
            });
          })}
          {this._renderRow('Push View Example', () => {
            this.props.navigator.push({
              title: 'Very Long Custom View Example Title',
              component: createExamplePage(null, ViewExample),
            });
          })}
          {this._renderRow('Custom title image Example', () => {
            this.props.navigator.push({
              title: 'Custom title image Example',
              titleImage: require('./relay.png'),
              component: createExamplePage(null, ViewExample),
            });
          })}
          {this._renderRow('Custom Right Button', () => {
            this.props.navigator.push({
              title: NavigatorIOSExample.title,
              component: EmptyPage,
              rightButtonTitle: 'Cancel',
              onRightButtonPress: () => this.props.navigator.pop(),
              passProps: {
                text: 'This page has a right button in the nav bar',
              }
            });
          })}
          {this._renderRow('Custom Right System Button', () => {
            this.props.navigator.push({
              title: NavigatorIOSExample.title,
              component: EmptyPage,
              rightButtonSystemIcon: 'bookmarks',
              onRightButtonPress: () => this.props.navigator.pop(),
              passProps: {
                text: 'This page has a right system button in the nav bar',
              }
            });
          })}
          {this._renderRow('Custom Left & Right Icons', () => {
            this.props.navigator.push({
              title: NavigatorIOSExample.title,
              component: EmptyPage,
              leftButtonTitle: 'Custom Left',
              onLeftButtonPress: () => this.props.navigator.pop(),
              rightButtonIcon: nativeImageSource({
                ios: 'NavBarButtonPlus',
                width: 17,
                height: 17
              }),
              onRightButtonPress: () => {
                AlertIOS.alert(
                  'Bar Button Action',
                  'Recognized a tap on the bar button icon',
                  [
                    {
                      text: 'OK',
                      onPress: () => console.log('Tapped OK'),
                    },
                  ]
                );
              },
              passProps: {
                text: 'This page has an icon for the right button in the nav bar',
              }
            });
          })}
          {this._renderRow('Custom Left & Right System Icons', () => {
            this.props.navigator.push({
              title: NavigatorIOSExample.title,
              component: EmptyPage,
              leftButtonSystemIcon: 'cancel',
              onLeftButtonPress: () => this.props.navigator.pop(),
              rightButtonSystemIcon: 'search',
              onRightButtonPress: () => {
                AlertIOS.alert(
                  'Bar Button Action',
                  'Recognized a tap on the bar button icon',
                  [
                    {
                      text: 'OK',
                      onPress: () => console.log('Tapped OK'),
                    },
                  ]
                );
              },
              passProps: {
                text: 'This page has an icon for the right button in the nav bar',
              }
            });
          })}
          {this._renderRow('Pop', () => {
            this.props.navigator.pop();
          })}
          {this._renderRow('Pop to top', () => {
            this.props.navigator.popToTop();
          })}
          {this._renderReplace()}
          {this._renderReplacePrevious()}
          {this._renderReplacePreviousAndPop()}
          {this._renderRow('Exit NavigatorIOS Example', this.props.onExampleExit)}
        </View>
        <View style={styles.line}/>
      </ScrollView>
    );
  }

  _renderReplace = () => {
    if (!this.props.depth) {
      // this is to avoid replacing the top of the stack
      return null;
    }
    return this._renderRow('Replace here', () => {
      var prevRoute = this.props.route;
      this.props.navigator.replace({
        title: 'New Navigation',
        component: EmptyPage,
        rightButtonTitle: 'Undo',
        onRightButtonPress: () => this.props.navigator.replace(prevRoute),
        passProps: {
          text: 'The component is replaced, but there is currently no ' +
            'way to change the right button or title of the current route',
        }
      });
    });
  };

  _renderReplacePrevious = () => {
    if (!this.props.depth || this.props.depth < 2) {
      // this is to avoid replacing the top of the stack
      return null;
    }
    return this._renderRow('Replace previous', () => {
      this.props.navigator.replacePrevious({
        title: 'Replaced',
        component: EmptyPage,
        passProps: {
          text: 'This is a replaced "previous" page',
        },
        wrapperStyle: styles.customWrapperStyle,
      });
    });
  };

  _renderReplacePreviousAndPop = () => {
    if (!this.props.depth || this.props.depth < 2) {
      // this is to avoid replacing the top of the stack
      return null;
    }
    return this._renderRow('Replace previous and pop', () => {
      this.props.navigator.replacePreviousAndPop({
        title: 'Replaced and Popped',
        component: EmptyPage,
        passProps: {
          text: 'This is a replaced "previous" page',
        },
        wrapperStyle: styles.customWrapperStyle,
      });
    });
  };

  _renderRow = (title: string, onPress: Function) => {
    return (
      <View>
        <TouchableHighlight onPress={onPress}>
          <View style={styles.row}>
            <Text style={styles.rowText}>
              {title}
            </Text>
          </View>
        </TouchableHighlight>
        <View style={styles.separator} />
      </View>
    );
  };
}

class NavigatorIOSExample extends React.Component {
  static title = '<NavigatorIOS>';
  static description = 'iOS navigation capabilities';
  static external = true;

  render() {
    const {onExampleExit} = this.props;
    return (
      <NavigatorIOS
        style={styles.container}
        initialRoute={{
          title: NavigatorIOSExample.title,
          component: NavigatorIOSExamplePage,
          passProps: {onExampleExit},
        }}
        tintColor="#008888"
      />
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  customWrapperStyle: {
    backgroundColor: '#bbdddd',
  },
  emptyPage: {
    flex: 1,
    paddingTop: 64,
  },
  emptyPageText: {
    margin: 10,
  },
  list: {
    backgroundColor: '#eeeeee',
    marginTop: 10,
  },
  group: {
    backgroundColor: 'white',
  },
  groupSpace: {
    height: 15,
  },
  line: {
    backgroundColor: '#bbbbbb',
    height: StyleSheet.hairlineWidth,
  },
  row: {
    backgroundColor: 'white',
    justifyContent: 'center',
    paddingHorizontal: 15,
    paddingVertical: 15,
  },
  separator: {
    height: StyleSheet.hairlineWidth,
    backgroundColor: '#bbbbbb',
    marginLeft: 15,
  },
  rowNote: {
    fontSize: 17,
  },
  rowText: {
    fontSize: 17,
    fontWeight: '500',
  },
});

module.exports = NavigatorIOSExample;

书籍推荐