React Native導(dǎo)航器

React Native 進(jìn)階(四)--導(dǎo)航器

導(dǎo)航器對(duì)比

如果你剛開始接觸,那么直接選擇Navigator就好。如果你只針對(duì)iOS平臺(tái)開發(fā),并且想和系統(tǒng)原生外觀一致,那么可以選擇NavigatorIOS。如果你想更好地管理導(dǎo)航棧,那么應(yīng)該嘗試一下NavigationExperimental。

Navigator

Navigator使用純JavaScript實(shí)現(xiàn)了一個(gè)導(dǎo)航棧,因此可以跨平臺(tái)工作,同時(shí)也便于定制。

Navigator可以在renderScene方法中根據(jù)當(dāng)前路由渲染不同的組件。默認(rèn)情況下新的場(chǎng)景會(huì)從屏幕右側(cè)滑進(jìn)來,但你也可以通過configureScene方法來管理這一行為。你還可以通過navigationBar屬性來配置一個(gè)跨場(chǎng)景的導(dǎo)航欄。但我們不推薦使用跨場(chǎng)景的navigationBar,它的代碼邏輯維護(hù)起來很困難!建議自己在場(chǎng)景中用View實(shí)現(xiàn)自定義的導(dǎo)航欄。

方法

如果你得到了一個(gè)navigator對(duì)象的引用,則可以調(diào)用許多方法來進(jìn)行導(dǎo)航:

  • getCurrentRoutes() - 獲取當(dāng)前棧里的路由,也就是push進(jìn)來,沒有pop掉的那些。
  • jumpBack() - 跳回之前的路由,當(dāng)然前提是保留現(xiàn)在的,還可以再跳回來,會(huì)給你保留原樣。
  • jumpForward() - 上一個(gè)方法不是調(diào)到之前的路由了么,用這個(gè)跳回來就好了。
  • jumpTo(route) - 跳轉(zhuǎn)到已有的場(chǎng)景并且不卸載。
  • push(route) - 跳轉(zhuǎn)到新的場(chǎng)景,并且將場(chǎng)景入棧,你可以稍后跳轉(zhuǎn)過去
  • pop() - 跳轉(zhuǎn)回去并且卸載掉當(dāng)前場(chǎng)景
  • replace(route) - 用一個(gè)新的路由替換掉當(dāng)前場(chǎng)景
  • replaceAtIndex(route, index) - 替換掉指定序列的路由場(chǎng)景
  • replacePrevious(route) - 替換掉之前的場(chǎng)景
  • resetTo(route) - 跳轉(zhuǎn)到新的場(chǎng)景,并且重置整個(gè)路由棧
  • immediatelyResetRouteStack(routeStack) - 用新的路由數(shù)組來重置路由棧
  • popToRoute(route) - pop到路由指定的場(chǎng)景,在整個(gè)路由棧中,處于指定場(chǎng)景之后的場(chǎng)景將會(huì)被卸載。
  • popToTop() - pop到棧中的第一個(gè)場(chǎng)景,卸載掉所有的其他場(chǎng)景。

這些都是navigator可以用的public method,就是跳轉(zhuǎn)用的,里面有些帶參數(shù)的XXX(route),這個(gè)route參數(shù)是什么呢,這個(gè)route就是:
renderScene={(route, navigator) =>
這里的route,最基本的route就是:

let route = {
  component: SampleComponent
}

屬性

configureScene function

可選的函數(shù),用來配置場(chǎng)景動(dòng)畫和手勢(shì)。會(huì)帶有兩個(gè)參數(shù)調(diào)用,一個(gè)是當(dāng)前的路由,一個(gè)是當(dāng)前的路由棧。然后它應(yīng)當(dāng)返回一個(gè)場(chǎng)景配置對(duì)象

(route, routeStack) => Navigator.SceneConfigs.FloatFromRight

  • Navigator.SceneConfigs.PushFromRight (默認(rèn))
  • Navigator.SceneConfigs.FloatFromRight
  • Navigator.SceneConfigs.FloatFromLeft
  • Navigator.SceneConfigs.FloatFromBottom
  • Navigator.SceneConfigs.FloatFromBottomAndroid
  • Navigator.SceneConfigs.FadeAndroid
  • Navigator.SceneConfigs.HorizontalSwipeJump
  • Navigator.SceneConfigs.HorizontalSwipeJumpFromRight
  • Navigator.SceneConfigs.VerticalUpSwipeJump
  • Navigator.SceneConfigs.VerticalDownSwipeJump

initialRoute object

定義啟動(dòng)時(shí)加載的路由。路由是導(dǎo)航欄用來識(shí)別渲染場(chǎng)景的一個(gè)對(duì)象。initialRoute必須是initialRouteStack中的一個(gè)路由。initialRoute默認(rèn)為initialRouteStack中最后一項(xiàng)。

initialRouteStack [object]

提供一個(gè)路由集合用來初始化。如果沒有設(shè)置初始路由的話則必須設(shè)置該屬性。如果沒有提供該屬性,它將被默認(rèn)設(shè)置成一個(gè)只含有initialRoute的數(shù)組。

navigationBar node

可選參數(shù),提供一個(gè)在場(chǎng)景切換的時(shí)候保持的導(dǎo)航欄。

navigator object

可選參數(shù),提供從父導(dǎo)航器獲得的導(dǎo)航器對(duì)象。

onDidFocus function

每當(dāng)導(dǎo)航切換完成或初始化之后,調(diào)用此回調(diào),參數(shù)為新場(chǎng)景的路由。

onWillFocus function

會(huì)在導(dǎo)航切換之前調(diào)用,參數(shù)為目標(biāo)路由。

renderScene function

必要參數(shù)。用來渲染指定路由的場(chǎng)景。調(diào)用的參數(shù)是路由和導(dǎo)航器。

(route, navigator) =><MySceneComponent title={route.title} navigator={navigator} />

sceneStyle View#style

將會(huì)應(yīng)用在每個(gè)場(chǎng)景的容器上的樣式。

例子

Navigator.js

import React from 'react';
import {
  View,
  Navigator
} from 'react-native';
import FirstPageComponent from './FirstPageComponent';

export default class Sample extends React.Component {
  render() {
    let defaultName = 'FirstPageComponent';
    let defaultComponent = FirstPageComponent;
    return (
      <Navigator
        initialRoute={{ name: defaultName, component: defaultComponent }}
        configureScene={(route) => { // 跳轉(zhuǎn)動(dòng)畫
          return Navigator.SceneConfigs.VerticalDownSwipeJump;
        }}
        renderScene={(route, navigator) => {
          let Component = route.component;
          // 這里有個(gè) { ...route.params },這個(gè)語(yǔ)法是把 routes.params 里的每個(gè)key 作為props的一個(gè)屬性
          return <Component {...route.params} navigator={navigator} />
        }} 
      />
    );
  }
} 
第10行: 一個(gè)初始首頁(yè)的component名字,比如我寫了一個(gè)component叫HomeComponent,
        那么這個(gè)name就是這個(gè)組件的名字[HomeComponent]了。  
第11行: 這個(gè)組件的Class,用來一會(huì)兒實(shí)例化成 <Component />標(biāo)簽
第14行: initialRoute={{ name: defaultName, component: defaultComponent }} 這個(gè)指定了默認(rèn)的頁(yè)面,
        也就是啟動(dòng)app之后會(huì)看到界面的第一屏。 需要填寫兩個(gè)參數(shù): name 跟 component。(注意這里填什么參數(shù)(參數(shù)名)純粹是自定義的,
        因?yàn)檫@個(gè)參數(shù)也是你自己發(fā)自己收,自己在renderScene方法中處理。這個(gè)示例用了兩個(gè)參數(shù),但其實(shí)真正使用的參數(shù)只有component)  
第15,16,17行: configureScene={() => {return Navigator.SceneConfigs.VerticalDownSwipeJump;}} 這個(gè)是頁(yè)面之間跳轉(zhuǎn)時(shí)候的動(dòng)畫,
        具體有哪些動(dòng)畫可以看node_modules/react-native/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js下的源代碼。
最后的幾行: renderScene={(route, navigator) => {let Component = route.component;return <Component {...route.params} navigator={navigator} />}},
        這里是每個(gè)人最疑惑的,我們先看到回調(diào)里的兩個(gè)參數(shù):route, navigator。通過打印我們發(fā)現(xiàn)route里其實(shí)就是我們傳遞的name,component這兩個(gè)貨,
        navigator是一個(gè)Navigator的對(duì)象,為什么呢,因?yàn)樗衟ush pop jump...等方法,這是我們等下用來跳轉(zhuǎn)頁(yè)面用的那個(gè)navigator對(duì)象。
        return <Component {...route.params} navigator={navigator} />  
        這里有一個(gè)判斷,也就是如果傳遞進(jìn)來的component存在,那我們就是返回一個(gè)這個(gè)component,結(jié)合前面 initialRoute 的參數(shù),我們就知道,
        這是一個(gè)會(huì)被render出來給用戶看到的component,然后navigator作為props傳遞給了這個(gè)component。

所以下一步,在這個(gè)FirstPageComponent里面,我們可以直接拿到這個(gè) props.navigator:

FirstPageComponent.js

import React from 'react';
import {
  View,
  Navigator,
  TouchableOpacity,
  Text
} from 'react-native';

import SecondPageComponent from './SecondPageComponent';

export default class FirstPageComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      id: 2,
      user: null,
    };
  }
  _pressButton() {
    let _this = this;
    const { navigator } = this.props;
    //為什么這里可以取得 props.navigator?請(qǐng)注意Navigator.js中:
    //<Component {...route.params} navigator={navigator} />
    //這里傳遞了navigator作為props
    if (navigator) {
      // 入棧~ 把SecondPageComponent頁(yè)面push進(jìn)棧,接著跳轉(zhuǎn)到SecondPageComponent
      navigator.push({
        name: 'SecondPageComponent',
        component: SecondPageComponent,
        //這個(gè) params 其實(shí)來自于Navigator 里的一個(gè)方法的參數(shù)
        params: {  //routes.params
          id: this.state.id,
          //從SecondPageComponent獲取user
          getUser: function (user) {
            _this.setState({
              user: user
            })
          }
        }
      })
    }
  }
  render() {
    if (this.state.user) {
      return (
        <View>
          <Text>用戶信息: {JSON.stringify(this.state.user)}</Text>
        </View>
      );
    } else {
      return (
        <View>
          <TouchableOpacity onPress={this._pressButton.bind(this)}>
            <Text>查詢ID為{this.state.id}的用戶信息</Text>
          </TouchableOpacity>
        </View>
      );
    }
  }
}

這個(gè)里面創(chuàng)建了一個(gè)可以點(diǎn)擊的區(qū)域,點(diǎn)擊可以跳到SecondPageComponent這個(gè)頁(yè)面,實(shí)現(xiàn)頁(yè)面的跳轉(zhuǎn)。
現(xiàn)在來創(chuàng)建SecondPageComponent,并且讓它可以再跳回FirstPageComponent:

SecondPageComponent.js

import React from 'react';
import {
  View,
  Navigator,
  Text,
  TouchableOpacity
} from 'react-native';

import FirstPageComponent from './FirstPageComponent';

const USER_MODELS = {
  1: { name: '小李', age: 18 },
  2: { name: '小明', age: 20 }
};

export default class SecondPageComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      id: null
    };
  }
  componentDidMount() {
    //這里獲取從FirstPageComponent傳遞過來的參數(shù): id
    this.setState({
      id: this.props.id
    });
  }
  _pressButton() {
    const { navigator } = this.props;
    if (this.props.getUser) {
      let user = USER_MODELS[this.props.id];
      this.props.getUser(user);
    }
    //出棧~ 把當(dāng)前的頁(yè)面pop掉,這里就返回到了上一個(gè)頁(yè)面:FirstPageComponent了
    if (navigator) {
      navigator.pop();
    }
  }
  
  render() {
    return (
      <View>
        <Text>獲得的參數(shù)(id): id={this.state.id}</Text>
        <TouchableOpacity onPress={this._pressButton.bind(this)}>
          <Text>點(diǎn)我跳回去</Text>
        </TouchableOpacity>
      </View>
    );
  }
}

傳遞參數(shù)和獲取參數(shù)

傳遞參數(shù)到新頁(yè)面

傳遞參數(shù)到新頁(yè)面,可以通過push。比如在一個(gè) press的事件里:

FirstPageComponent.js

...
constructor(props) {
  super(props);
  this.state = {
    id: 2
  };
}
_pressButton() {
  ...
    navigator.push({
      name: 'SecondPageComponent',
      component: SecondPageComponent,
      //這個(gè) params 其實(shí)來自于Navigator 里的一個(gè)方法的參數(shù)
      params: {
        id: this.state.id
      }
    })
  ...
}

params的來歷:

//Navigator.js
...
<Navigator
  initialRoute={{ name: defaultName, component: defaultComponent }}
  configureScene={() => {
    return Navigator.SceneConfigs.VerticalDownSwipeJump;
  }}
  renderScene={(route, navigator) => {
    let Component = route.component;
    if(route.component) {
        //這里有個(gè) { ...route.params }
        return <Component {...route.params} navigator={navigator} />
    }
  }} 
/>
...

{ ...route.params }語(yǔ)法是把 routes.params 里的每個(gè)key 作為props的一個(gè)屬性:

//FirstPageComponent.js
...
navigator.push({
    name: 'SecondPageComponent',
    component: SecondPageComponent,
    params: {  //routes.params
        id: this.state.id
    }
});
...

這里的 params.id 就變成了 <Component id={routes.params.id} navigator={navigator}> 里的id屬性(props)傳遞給了下一個(gè)頁(yè)面。

//SecondPageComponent.js
...
componentDidMount() {
  //這里獲取從FirstPageComponent傳遞過來的參數(shù): id
  this.setState({
    id: this.props.id
  });
}
...
render() {
  return (
    <View>
      <Text>獲得的參數(shù): id={ this.state.id }</Text>
      <TouchableOpacity onPress={this._pressButton.bind(this)}>
        <Text>點(diǎn)我跳回去</Text>
      </TouchableOpacity>
    </View>
  );
}
返回參數(shù)到之前頁(yè)面

返回的時(shí)候,也需要傳遞參數(shù)回上一個(gè)頁(yè)面。但是navigator.pop()并沒有提供參數(shù),因?yàn)閜op()只是從 [路由1,路由2,路由3。。。]里把最后一個(gè)路由踢出去的操作,并不支持傳遞參數(shù)給倒數(shù)第二個(gè)路由,這里要用到一個(gè)概念,把上一個(gè)頁(yè)面的實(shí)例或者回調(diào)方法,作為參數(shù)傳遞到當(dāng)前頁(yè)面來,在當(dāng)前頁(yè)面操作上一個(gè)頁(yè)面的state:

比如FirstPageComponent傳遞id到SecondPageComponent,然后SecondPageComponent返回user信息給FirstPageComponent:

//FirstPageComponent.js
...
constructor(props) {
  super(props);
  this.state = {
    id: 2,
    user: null,
  }
}
...
_pressButton() {
    let _this = this;
    ...
      params: {  //routes.params
        id: this.state.id,
        //從SecondPageComponent獲取user
        getUser: function (user) {
          _this.setState({
            user: user
          })
        }
      }
...
render() {
  if (this.state.user) {
    return (
      <View>
        <Text>用戶信息: {JSON.stringify(this.state.user)}</Text>
      </View>
    );
  } else {
    return (
      <View>
        <TouchableOpacity onPress={this._pressButton.bind(this)}>
          <Text>查詢ID為{this.state.id}的用戶信息</Text>
        </TouchableOpacity>
      </View>
    );
  }
}
//SecondPageComponent.js
...
const USER_MODELS = {
  1: { name: '小李', age: 18 },
  2: { name: '小明', age: 20 }
};

export default class SecondPageComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      id: null
    };
  }
  componentDidMount() {
    //這里獲取從FirstPageComponent傳遞過來的參數(shù): id
    this.setState({
      id: this.props.id
    });
  }
  _pressButton() {
    const { navigator } = this.props;
    if (this.props.getUser) {
      let user = USER_MODELS[this.props.id];
      this.props.getUser(user);
    }
    //出棧~ 把當(dāng)前的頁(yè)面pop掉,這里就返回到了上一個(gè)頁(yè)面:FirstPageComponent了
    if (navigator) {
      navigator.pop();
    }
  }
}
...

NavigatorIOS

如果你只針對(duì)iOS平臺(tái)開發(fā),那么可以考慮使用NavigatorIOS。它是基于 UINavigationController封裝的。

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

用法類似Navigator,NavigatorIOS也使用路由對(duì)象來描述場(chǎng)景,但有一些重要區(qū)別。其中要渲染的組件在路由對(duì)象的component字段中指定,要給目標(biāo)組件傳遞的參數(shù)則寫在passProps中。被渲染的component都會(huì)自動(dòng)接受到一個(gè)名為navigator的屬性,你可以直接調(diào)用此對(duì)象(this.props.navigator)的push和pop方法。
由于NavigatorIOS使用的是原生的UIKit導(dǎo)航,所以它會(huì)自動(dòng)渲染一個(gè)帶有返回按鈕和標(biāo)題的導(dǎo)航欄。

你還可以看看react-native-navigation,這是一個(gè)第三方的組件,旨在于提供原生的跨平臺(tái)的導(dǎo)航組件。

NavigationExperimental

Navigator和NavigatorIOS都是有狀態(tài)的組件。如果你在app中多處使用這些組件,那么維護(hù)工作就會(huì)變得非常麻煩。NavigationExperimental以不同的方式實(shí)現(xiàn)了導(dǎo)航,它可以使用任何視圖來作為導(dǎo)航視圖,同時(shí)還用到了規(guī)約函數(shù)(reducer)自頂向下地管理狀態(tài)。正如名字中的Experimental(實(shí)驗(yàn))所示,這一組件的整體實(shí)現(xiàn)具有一定的實(shí)驗(yàn)性,但仍然建議你嘗試一下用它去更好地管理應(yīng)用的導(dǎo)航。

<NavigationCardStack
  onNavigateBack={onPopRouteFunc}
  navigationState={myNavigationState}
  renderScene={renderSceneFun}
/>

引入NavigationExperimental的步驟和React Native中的其他組件一樣。在引入此組件之后,還可以進(jìn)一步解構(gòu)其中一些有用的子組件,比如這里我們會(huì)從中解構(gòu)NavigationCardStack和 NavigationStateUtils這兩個(gè)子組件。

import React, { Component } from 'react';
import { NavigationExperimental } from 'react-native';

const {
  CardStack: NavigationCardStack,
  StateUtils: NavigationStateUtils,
} = NavigationExperimental;

NavigationExperimental的實(shí)現(xiàn)機(jī)制與Navigator和NavigatorIOS有所不同,用它來構(gòu)建導(dǎo)航棧還需要一些額外的步驟。

第一步:定義初始狀態(tài)和根容器

首先創(chuàng)建一個(gè)新組件,我們會(huì)把它作為根容器,并在這里定義初始狀態(tài)。導(dǎo)航棧會(huì)定義在navigationState字段中,其中也包含了初始的路由定義:

import React, { Component } from 'react';
import { NavigationExperimental } from 'react-native';

const {
  CardStack: NavigationCardStack,
  StateUtils: NavigationStateUtils,
} = NavigationExperimental;

class Sample extends Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      // 定義初始的導(dǎo)航狀態(tài)
      navigationState: {
        index: 0, // 現(xiàn)在是第一頁(yè)(索引從0開始)
        routes: [{key: '最初的場(chǎng)景'}], // 初始僅設(shè)定一個(gè)路由
      },
    };
    // 稍后再補(bǔ)充此函數(shù)的實(shí)現(xiàn)細(xì)節(jié)
    this._onNavigationChange = this._onNavigationChange.bind(this);
  }
  _onNavigationChange(type) {
    // 稍后再補(bǔ)充此函數(shù)的實(shí)現(xiàn)細(xì)節(jié)
  }
  _exit() {
    //exit()實(shí)現(xiàn)
  }
  render() {
    return (
      <Text>這是一段占位的文字。稍后會(huì)在這里渲染導(dǎo)航。</Text>
    );
  }
}

現(xiàn)在我們定義了一個(gè)有狀態(tài)的組件,暫時(shí)是無用的。我們的初始狀態(tài)包含了一個(gè)路由對(duì)象,以及當(dāng)前頁(yè)面的索引值。但是這看起來跟Navigator的初始路由定義好像沒什么區(qū)別!回憶一下navigator對(duì)象提供了push和pop操作,看起來也非常直觀。但是前面我們說過了,現(xiàn)在我們會(huì)在根容器上使用規(guī)約函數(shù)來管理狀態(tài),下面繼續(xù)。

第二步:規(guī)約導(dǎo)航狀態(tài)

NavigationExperimental內(nèi)置了一些有用的規(guī)約函數(shù)(reducer),都放在NavigationStateUtils中。我們現(xiàn)在要用的兩個(gè)就是push和pop了。它們接受一個(gè)navigationState對(duì)象參數(shù),然后返回新的navigationState對(duì)象。

據(jù)此我們可以這樣來編寫_onNavigationChange函數(shù),在其中判斷"push"和"pop"的行為,并分別規(guī)約對(duì)應(yīng)的狀態(tài)。

_onNavigationChange(type) {
  // 從state中解構(gòu)出navigationState
  let {navigationState} = this.state;
  switch (type) {
    case 'push':
      // push一個(gè)新路由,在這里就是一個(gè)帶有key屬性的對(duì)象。
      // key必須要確保唯一性
      const route = {key: 'Route-' + Date.now()};
      // 調(diào)用NavigationStateUtils提供的push規(guī)約函數(shù)
      navigationState = NavigationStateUtils.push(navigationState, route);
      break;
    case 'pop':
      // 使用pop函數(shù)來彈出當(dāng)前路由
      navigationState = NavigationStateUtils.pop(navigationState);
      break;
  }
  // 如果沒有實(shí)際變化,則NavigationStateUtils會(huì)返回同樣的`navigationState`
  // 我們只會(huì)更新確實(shí)發(fā)生變化的狀態(tài)
  if (this.state.navigationState !== navigationState) {
    // 請(qǐng)記住更新狀態(tài)必須通過setState()方法!
    this.setState({navigationState});
    // 簡(jiǎn)單講解一下上面那一句ES6語(yǔ)法
    // 如果key和value的字面一樣,那么可以簡(jiǎn)寫成一個(gè),等同于下面的寫法:
    // this.setState({navigationState: navigationState});
  }
}

到這里,我們已經(jīng)觸碰到了NavigationExperimental的精髓所在。這里我們只處理了兩種行為,實(shí)際開發(fā)中行為可能更復(fù)雜,比如可能會(huì)考慮后退(back)行為,又或者是tab間的切換過渡行為等等。

我們現(xiàn)在還沒寫初始場(chǎng)景和實(shí)際的導(dǎo)航器,不過別急,我們一步一步來。

第三步:定義場(chǎng)景

為方便起見我們先定義一個(gè)Row(行)組件。其中顯示了一些文字,并帶有點(diǎn)擊事件。

class TappableRow extends Component {
  render() {
    return (
      <TouchableHighlight
        style={styles.row}
        underlayColor="#D0D0D0"
        onPress={this.props.onPress}>
        <Text style={styles.buttonText}>
          {this.props.text}
        </Text>
      </TouchableHighlight>
    );
  }
}

現(xiàn)在來定義實(shí)際的場(chǎng)景。其中用到了一個(gè)ScrollView來顯示一個(gè)垂直列表,第一行顯示當(dāng)前路由對(duì)象的key字段值,后兩行用來點(diǎn)擊后調(diào)用導(dǎo)航器的push和pop方法。

class MyVeryComplexScene extends Component {
  render() {
    return (
      <ScrollView style={styles.scrollView}>
        <Text style={styles.row}>
          路由: {this.props.route.key}
        </Text>
        <TappableRow
          text="加載下一個(gè)場(chǎng)景"
          onPress={this.props.onPushRoute}/>
        <TappableRow
          text="返回上一個(gè)場(chǎng)景"
          onPress={this.props.onPopRoute}/>
      </ScrollView>
    );
  }
}

第四步:創(chuàng)建導(dǎo)航棧

我們之前已經(jīng)定義了狀態(tài)和管理狀態(tài)的規(guī)約函數(shù),現(xiàn)在可以創(chuàng)建導(dǎo)航器組件了。在寫導(dǎo)航器的同時(shí),我們可以使用當(dāng)前路由的屬性來配置場(chǎng)景并渲染它了。

class MyVerySampleNavigator extends Component {
  // 在這里綁定一些導(dǎo)航用的方法
  constructor(props, context) {
    super(props, context);
    this._onPushRoute = this.props.onNavigationChange.bind(null, 'push');
    this._onPopRoute = this.props.onNavigationChange.bind(null, 'pop');
    this._renderScene = this._renderScene.bind(this);
  }
  // 現(xiàn)在我們終于可以使用“NavigationCardStack”來渲染場(chǎng)景。
  render() {
    return (
      <NavigationCardStack
        onNavigateBack={this._onPopRoute}
        navigationState={this.props.navigationState}
        renderScene={this._renderScene}
        style={styles.navigator}
      />
    );
  }
  // 根據(jù)路由來渲染場(chǎng)景
  // `sceneProps`的具體結(jié)構(gòu)定義在`NavigationTypeDefinition`的`NavigationSceneRendererProps`中
  // 這里你可以根據(jù)路由的不同來返回不同的場(chǎng)景組件,我們這里為了簡(jiǎn)要說明,始終只返回這一個(gè)場(chǎng)景組件
  _renderScene(sceneProps) {
    return (
      <MyVeryComplexScene
        route={sceneProps.scene.route}
        onPushRoute={this._onPushRoute}
        onPopRoute={this._onPopRoute}
        onExit={this.props.onExit}
      />
    );
  }
}

最后把我們新做的導(dǎo)航器放到根容器中:

class Sample extends Component {
  // 這里省略了constructor和其他的方法
  render() {
    return (
      <MyVerySampleNavigator
        navigationState={this.state.navigationState}
        onNavigationChange={this._onNavigationChange}
        onExit={this._exit}
      />
    );
  }
}

別忘了引入組件和樣式

import { NavigationExperimental, PixelRatio, ScrollView, StyleSheet, Text, TouchableHighlight } from 'react-native';

const styles = StyleSheet.create({
  navigator: {
    flex: 1,
  },
  scrollView: {
    marginTop: 64
  },
  row: {
    padding: 15,
    backgroundColor: 'white',
    borderBottomWidth: 1 / PixelRatio.get(),
    borderBottomColor: '#CDCDCD',
  },
  rowText: {
    fontSize: 17,
  },
  buttonText: {
    fontSize: 17,
    fontWeight: '500',
  },
});

React Native學(xué)習(xí)筆記--進(jìn)階(一)--嵌入到Android原生應(yīng)用中、組件的生命周期、顏色、圖片、觸摸事件
React Native學(xué)習(xí)筆記--進(jìn)階(二)--動(dòng)畫
React Native學(xué)習(xí)筆記--進(jìn)階(三)--定時(shí)器、直接操作(setNativeProps)、調(diào)試
React Native學(xué)習(xí)筆記--進(jìn)階(四)--導(dǎo)航器
React Native學(xué)習(xí)筆記--進(jìn)階(五)--性能、升級(jí)、特定平臺(tái)代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容