《React-Native系列》43、通用容器和導航設計方案

來源:互聯網
上載者:User

在現階段我們的RN實踐都是基於發行過的APP,譬如將從某個入口進入的子模組都替換成RN頁面。那麼我們可以將這個子模組設計成一個通用RN容器,所有的RN頁面都在RN容器內部跳轉。


RN容器在iOS使用UIViewController、Android使用Activity或者Fragment,載入bundle檔案,正常情況下,一個模組只有一個bundle檔案。

要實現頁面的跳轉,我們可以使用Navigator組件,具體使用可以參考:http://blog.csdn.net/codetomylaw/article/details/52059493


還有幾個問題需要解決:

1、導覽列

在原生App中導覽列通常是統一管理的,那麼在通用容器中,我們可以定義一個通用的RN導航。

2、Native跳轉RN容器

使用正常的Native跳轉方式即可,譬如在Android中 startActivity 。

3、RN容器返回Native介面

由於導覽列已經是RN介面編寫的,那麼Native端就需要提供一個橋接的方法給RN調用,橋接方法需要實現的邏輯:finish掉初始化的RN容器

4、處理安卓系統返回鍵

詳細見Demo代碼


好,我們通過一個簡單的Demo來示範。

我們實現的效果是

1、從Native頁面跳轉RN頁面A,RN頁面A是由RN容器載入,點擊左上方可以返回到Native介面

2、點擊RN頁面A中的“跳轉詳情”可以跳轉到RN頁面B

3、點擊RN頁面B中的左上方或安卓物理返回鍵,可以返回到RN頁面A

4、點擊RN頁面B中的左上方或安卓物理返回鍵,可以阻斷頁面的返回,實現我們自己的邏輯

5、點擊RN頁面B中的分享,可以調用回調


頁面A如下圖:

     

頁面B如下圖:




導航組件代碼如下:Nav.js

import React, { Component } from 'react';import {  StyleSheet,  View,  Text,  Image,  TouchableOpacity,  Platform,  NativeModules,} from 'react-native';const {CommonDispatcher} = NativeModules;//通用瀏覽組件export default class Nav extends Component {  constructor(props) {    super(props);    height = (Platform.OS === 'ios') ? 64 : 45;    leftWidth = 60;    rightWidth = 60;  }  //控制返回事件,navigator返回 或 返回到原生頁面  back() {    const { navigator } = this.props;    if(navigator) {      const routers = navigator.getCurrentRoutes();      if (routers.length >1) {        navigator.pop();      }else{        //此處為橋接,需要finish 掉RN殼,跳轉到原生頁面        CommonDispatcher.toBack({});      }    }  }  //左上方事件  leftCallBack() {    if (this.props.leftCallBack) {      this.props.leftCallBack();    }else {      this.back();    }  }  //右上方事件  rightCallBack(){      if (this.props.rightCallBack) {          this.props.rightCallBack();      }  }  render() {    //左邊返回圖片可隱藏    let leftView = this.props.hiddenBack ?     <View style={styles.leftView} />    :(      <TouchableOpacity onPress={this.leftCallBack.bind(this)}>        <View style={styles.leftView}>          <Image source={{uri:"nav_back"}} style={styles.image}/>        </View>      </TouchableOpacity>);    //標題現在只支援文本,樣式後續也可支援修改    let centerView = <Text style={styles.title}>{this.props.title}</Text>;    //右上方地區目前只支援文本,後續可支援圖片或圖文    let rightView = (        <TouchableOpacity onPress={this.rightCallBack.bind(this)}>          <Text style={styles.rightTitle}>{this.props.rightTitle}</Text>        </TouchableOpacity>);    return (      <View style={styles.container} height={height}  backgroundColor={this.props.backgroundColor}>       <View style={styles.leftView}  width={leftWidth} >{leftView}</View>       <View style={styles.centerView} >{centerView}</View>       <View style={styles.rightView} width={rightWidth} >{rightView}</View>      </View>    );  }}const styles = StyleSheet.create({  container: {    justifyContent:'space-between',    flexDirection:'row',    alignItems:'center',    paddingTop:(Platform.OS === 'ios') ? 20 : 0,  },  leftView:{      flexDirection:'row',      alignItems:'center',  },  rightView:{      flexDirection:'row',      alignItems:'center',      justifyContent:'flex-end',  },  centerView:{      flex:1,      flexDirection:'row',      alignItems:'center',      justifyContent:'center',  },  image: {    marginLeft:20,    width:15,    height:15,  },  title: {    fontSize:17,    color:'#ffffff',  },  rightTitle: {    marginRight:15,    color:'white'  },});


容器組件代碼如下(HomePage也就是RN頁面A):page.js 

'use strict';import React, { Component } from 'react';import {  Platform,  Navigator,  BackAndroid,  NativeModules,  View,  Text,  AppRegistry,  TouchableOpacity,} from 'react-native';import Nav from './Nav.js';import DetailPage from './DetailPage';const {CommonDispatcher} = NativeModules;export default class PageIndex extends Component {  constructor(props) {    super(props);  }  componentWillMount() {    if (Platform.OS === 'android') {      //監聽安卓物理按鍵返回      BackAndroid.addEventListener('hardwareBackPress', this.onBackAndroid);    }  }  componentWillUnmount() {    if (Platform.OS === 'android') {      BackAndroid.removeEventListener('hardwareBackPress', this.onBackAndroid);    }  }  //處理安卓物理back鍵  onBackAndroid = () => {    let nav = this.navigator;    let routers = nav.getCurrentRoutes();    // 當前頁面不為root頁面時的處理    if (routers.length >1) {      let top = routers[routers.length - 1];      let handleBack = top.handleBack;      if (handleBack) {        // 路由或組件上決定這個介面自行處理back鍵        handleBack();        return true;      }      // 預設處理      nav.pop();      return true;    }    return false;  };  render() {    return (      <Navigator        ref={ nav => { this.navigator = nav; }}        initialRoute={{ name: "HomePage", component: HomePage }}        configureScene={(route) => {          return Navigator.SceneConfigs.PushFromRight;        }}        renderScene={(route, navigator) => {          let Component = route.component;          return <Component {...route.params} navigator={navigator} />        }} />    );  }}//這是一個使用了通用瀏覽的測試頁面class HomePage extends Component {  toDetailPage(){    const { navigator } = this.props;    if(navigator) {        navigator.push({            name: 'DetailPage',            component: DetailPage,            params:{              rightTitle:"分享"            }        })    }  }  render(){    return (        <View style={{flex:1}}>          <Nav {...this.props} ref='nav'  title='通用瀏覽Home' backgroundColor='#e6454a'/>          <TouchableOpacity onPress={this.toDetailPage.bind(this)} style={{backgroundColor:'#f2f2f2',marginTop:20,justifyContent:'center',alignItems:'center',}}>            <Text style={{fontSize:28,color:'#998462',textAlign:'center',}}>跳轉詳情</Text>          </TouchableOpacity>        </View>    );  }}AppRegistry.registerComponent('你自己的模組名', () => PageIndex);



RN頁面B代碼如下:DetailPage.js 

'use strict';import React, { Component } from 'react';import {  View,  Text,} from 'react-native';import Nav from './Nav.js';export default class DetailPage extends Component {  constructor(props) {      super(props);      let navigator = this.props.navigator;      if (navigator) {        let routes = navigator.getCurrentRoutes(); //nav是導航器對象        let lastRoute = routes[routes.length - 1]; // 當前頁面對應的route對象        lastRoute.handleBack = this.leftCallBack.bind(this);//設定route對象的hanleBack屬性      }  }  /**   * 情境:編輯頁面,點擊物理或左上方返回,需要提示“確定放棄修改嗎。”   */  leftCallBack(){    let logic = false;//你可以修改為true    if(logic){      alert("我不想返回");    }else{      this.refs.nav.back();    }  }  render(){    return (        <View style={{flex:1}}>          <Nav {...this.props} ref='nav' leftCallBack={this.leftCallBack.bind(this)}  rightCallBack={()=>{alert('分享')}} title='通用瀏覽Detail' backgroundColor='#e6454a'/>          <View style={{flex:1,backgroundColor:'#f2f2f2',justifyContent:'center',alignItems:'center',}}>            <Text style={{fontSize:28,color:'#998462',textAlign:'center',}}>我只是容器裡的一個RN頁面</Text>          </View>        </View>    );  }}


好,這樣就基本實現了通用的RN容器和導航,當然還有一些地方可以最佳化。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.