原文發(fā)布于CSDN,地址:查看原文
在現(xiàn)階段我們的RN實踐都是基于已發(fā)布過的APP待锈,譬如將從某個入口進入的子模塊都替換成RN頁面漠其。那么我們可以將這個子模塊設計成一個通用RN容器,所有的RN頁面都在RN容器內部跳轉竿音。
RN容器在iOS使用UIViewController和屎、Android使用Activity或者Fragment,加載bundle文件春瞬,正常情況下柴信,一個模塊只有一個bundle文件。
要實現(xiàn)頁面的跳轉宽气,我們可以使用Navigator組件随常,具體使用可以參考:http://blog.csdn.net/codetomylaw/article/details/52059493
還有幾個問題需要解決:
1、導航欄
在原生App中導航欄通常是統(tǒng)一管理的萄涯,那么在通用容器中绪氛,我們可以定義一個通用的RN導航。
2涝影、Native跳轉RN容器
使用正常的Native跳轉方式即可枣察,譬如在Android中 startActivity 。
3燃逻、RN容器返回Native界面
由于導航欄已經是RN界面編寫的询件,那么Native端就需要提供一個橋接的方法給RN調用,橋接方法需要實現(xiàn)的邏輯:finish掉初始化的RN容器
4唆樊、處理安卓系統(tǒng)返回鍵
詳細見Demo代碼
好宛琅,我們通過一個簡單的Demo來演示。
我們實現(xiàn)的效果是
1逗旁、從Native頁面跳轉RN頁面A嘿辟,RN頁面A是由RN容器加載,點擊左上角可以返回到Native界面
2片效、點擊RN頁面A中的“跳轉詳情”可以跳轉到RN頁面B
3红伦、點擊RN頁面B中的左上角或安卓物理返回鍵,可以返回到RN頁面A
4淀衣、點擊RN頁面B中的左上角或安卓物理返回鍵昙读,可以阻斷頁面的返回,實現(xiàn)我們自己的邏輯
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>);
//標題現(xiàn)在只支持文本艺沼,樣式后續(xù)也可支持修改
let centerView = <Text style={styles.title}>{this.props.title}</Text>;
//右上角區(qū)域目前只支持文本,后續(xù)可支持圖片或圖文
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') {
//監(jiān)聽安卓物理按鍵返回
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>
);
}
}
好盛杰,這樣就基本實現(xiàn)了通用的RN容器和導航挽荡,當然還有一些地方可以優(yōu)化。
《React-Native系列》前42篇博文見http://www.reibang.com/p/34ef5d19ea12