ReactNative之Navigator

code_xzh發表於2016-09-22

移動應用很少只包含一個頁面。從你新增第二個頁面開始,就得考慮如何管理多個頁面間的跳轉了。

導航器正是為此而生。它可以管理多個頁面間的跳轉,也包含了一些常見的過渡動畫,包括水平翻頁、垂直彈出等等。

Navigator

React Native目前有幾個內建的導航器元件,一般來說我們首推Navigator。它使用純JavaScript實現了一個導航棧,因此可以跨平臺工作,同時也便於定製。

場景(Scene)的概念與使用

無論是View中包含Text,還是一個排滿了圖片的ScrollView,渲染各種元件現在對你來說應該已經得心應手了。這些擺放在一個螢幕中的元件,就共同構成了一個“場景(Scene)”。

場景簡單來說其實就是一個全屏的React元件。與之相對的是單個的TextImage又或者是你自定義的什麼元件,僅僅佔據頁面中的一部分。你其實已經不知不覺地接觸到了場景——在前面的教程中,“編寫HelloWorld”“使用Flexbox佈局”“如何使用ListView”中的元件都是完整的場景示例。

下面我們來定義一個僅顯示一些文字的簡單場景。建立一個名為“MyScene.js”的檔案,然後貼上如下程式碼:

import React, { Component } from `react`;
import { View, Text } from `react-native`;

export default class MyScene extends Component {
  static get defaultProps() {
    return {
      title: `MyScene`
    };
  }

  render() {
    return (
      <View>
        <Text>Hi! My name is {this.props.title}.</Text>
      </View>
    )
  }
}

注意元件宣告前面的export default關鍵字。它的意思是匯出(export)當前元件,以允許其他元件引入(import)和使用當前元件,就像下面這樣(下面的程式碼你可以寫在index.ios.js或是index.android.js中):

import React, { Component } from `react`;
import { AppRegistry } from `react-native`;

// ./MyScene表示的是當前目錄下的MyScene.js檔案,也就是我們剛剛建立的檔案
// 注意即便當前檔案和MyScene.js在同一個目錄中,"./"兩個符號也是不能省略的!
// 但是.js字尾是可以省略的

import MyScene from `./MyScene`;

class YoDawgApp extends Component {
  render() {
    return (
      <MyScene />
    )
  }
}

AppRegistry.registerComponent(`YoDawgApp`, () => YoDawgApp);

我們現在已經建立了只有單個場景的App。其中的MyScene同時也是一個可複用的Reac元件的例子。

使用Navigator

場景已經說的夠多了,下面我們開始嘗試導航跳轉。首先要做的是渲染一個Navigator元件,然後通過此元件的renderScene屬性方法來渲染其他場景。

render() {
  return (
    <Navigator
      initialRoute={{ title: `My Initial Scene`, index: 0 }}
      renderScene={(route, navigator) => {
        <MyScene title={route.title} />
      }}
    />
  );
}

使用導航器經常會碰到“路由(route)”的概念。“路由”抽象自現實生活中的路牌,在RN中專指包含了場景資訊的物件。renderScene方法是完全根據路由提供的資訊來渲染場景的。你可以在路由中任意自定義引數以區分標記不同的場景,我們在這裡僅僅使用title作為演示。

將場景推入導航棧

要過渡到新的場景,你需要了解pushpop方法。這兩個方法由navigator物件提供,而這個物件就是上面的renderScene方法中傳遞的第二個引數。 我們使用這兩個方法來把路由物件推入或彈出導航棧。

navigator.push({
  title: `Next Scene`,
  index: 1,
});

navigator.pop();

下面是一個更完整的示例:

import React, { Component, PropTypes } from `react`;
import { Navigator, Text, TouchableHighlight, View } from `react-native`;

export default class SimpleNavigationApp extends Component {
  render() {
    return (
      <Navigator
        initialRoute={{ title: `My Initial Scene`, index: 0 }}
        renderScene={(route, navigator) =>
          <MyScene
            title={route.title}

            // 推入新場景所呼叫的方法           
            onForward={() => {    
              const nextIndex = route.index + 1;
              navigator.push({
                title: `Scene ` + nextIndex,
                index: nextIndex,
              });
            }}

            // 返回上一個場景所呼叫的方法
            onBack={() => {
              if (route.index > 0) {
                navigator.pop();
              }
            }}
          />
        }
      />
    )
  }
}

class MyScene extends Component {
  static propTypes = {
    title: PropTypes.string.isRequired,
    onForward: PropTypes.func.isRequired,
    onBack: PropTypes.func.isRequired,
  }
  render() {
    return (
      <View>
        <Text>Current Scene: { this.props.title }</Text>
        <TouchableHighlight onPress={this.props.onForward}>
          <Text>Tap me to load the next scene</Text>
        </TouchableHighlight>
        <TouchableHighlight onPress={this.props.onBack}>
          <Text>Tap me to go back</Text>
        </TouchableHighlight>
      </View>
    )
  }
}

在這個例子中,MyScene通過title屬性接受了路由物件中的title值。它還包含了兩個可點選的元件TouchableHighlight,會在點選時分別呼叫通過props傳入的onForwardonBack方法,而這兩個方法各自呼叫了navigator.push()navigator.pop(),從而實現了場景的變化。


相關文章