在上一節Navigation組件,我們使用系統提供的導航組件做了一個跳轉的例子,不過其實戰能力不強,這里推薦一個超牛逼的第三方庫:react-navigation。在講react-navigation之前,我們先看一下常用的導航組件。
導航控件
常見的導航主要分為三種:
1.StackNavigator :類似於普通的Navigator,屏幕上方導航欄
2.TabNavigator:obviously, 相當於iOS里面的TabBarController,屏幕下方標簽欄
3.DrawerNavigator:抽屜效果,左側滑出這種效果。
Navigation 使用
在你使用navigation的每一個界面navigation都提供相關的屬性和響應方法,常見的有:
navigate 定義跳轉到另一個頁面
調用此方法去鏈接你的其他界面,主要有以下參數:
·routeName- 目標路由名稱,將在你的app router中注冊
·params-將參數合並到目標router中
·action-(高級)sub-action ,如果該界面是一個navigator的話,將運行這個sub-action
例如:
class HomeScreen extends React.Component { render() { const {navigate} = this.props.navigation; return ( <View> <Text>This is the home screen of the app</Text> <Button onPress={() => navigate('Profile', {name: 'Brent'})} title="點擊我跳轉" /> </View> ) } }
state當前路由狀態
每個界面通過this.props.navigation.state去訪問它的router,state其中包括了:
·routeName - router配置的名稱
·key-用來區分router的唯一標示
·params-可選的一些string參數
setParams-更改router中的參數
該方法允許界面更改router中的參數,可以用來動態的更改header的內容
goBack-返回,pop回上一級
dispatch -使用dispatch可以向任何navigation傳遞一些其他的action,主要支持的action有
Navigate使用
例如:
import { NavigationActions } from 'react-navigation' const navigationAction = NavigationActions.navigate({ routeName: 'Profile', params: {}, // navigate can have a nested navigate action that will be run inside the child router action: NavigationActions.navigate({ routeName: 'SubProfileRoute'}) }) this.props.navigation.dispatch(navigationAction)
Reset
Reset方法會擦除掉所有的導航狀態,並且使用新的結果替代。
import { NavigationActions } from 'react-navigation' const resetAction = NavigationActions.reset({ index: 0, actions: [ NavigationActions.navigate({ routeName: 'Profile'}) ] }) this.props.navigation.dispatch(resetAction)
SetParams
為指定的router更新參數,該參數必須是已經存在於router的param中。
import { NavigationActions } from 'react-navigation' const setParamsAction = NavigationActions.setParams({ params: {}, // these are the new params that will be merged into the existing route params // The key of the route that should get the new params key: 'screen-123', }) this.props.navigation.dispatch(setParamsAction)
StackNavigator使用
StackNavigator使用比較簡單,看一個常見的例子:
class MyHomeScreen extends React.Component { static navigationOptions = { title: 'Home', //設置navigator的title } render() { return ( //button的onPress方法,實現點擊跳轉界面,並且傳遞參數name:Lucy <Button onPress={() => this.props.navigation.navigate('Profile', {name: 'Lucy'})} title="Go to Lucy's profile" /> ); } } //生成路由關系 const ModalStack = StackNavigator({ Home: { //對應界面MyHomeScreen screen: MyHomeScreen, }, Profile: { path: 'people/:name', screen: MyProfileScreen, }, });
StackNavigatorConfig
option for the route(路由選項):
·initialRouteName -為stack設置默認的界面,必須和route configs里面的一個key匹配。
·initialRouteParams - 初始路由的參數。
·navigationOptions- 屏幕導航的默認選項。
·paths-route config里面路徑設置的映射。
Visual Option(視覺選項):
·mode- 定義渲染(rendering)和轉換(transitions)的模式,兩種選項:
1) card-使用標准的iOS和Android的界面切換,這是默認的。
2)modal- 僅在iOS端有用,即模態出該視圖。
·headerMode- 指定header應該如何被渲染,選項:
1)float- 共用一個header 意思就是有title文字漸變效果。
2)screen- 各用各的header 意思就是沒有title文字漸變效果。
3)none- 沒有header。
·cardStyle- 使用該屬性繼承或者重載一個在stack中的card的樣式。
·onTransitionStart- 一個函數,在換場動畫開始的時候被激活。
·onTransitionEnd- 一個函數,在換場動畫結束的時候被激活。
Navigation Options
你還可以定義一個靜態的navigationOptions在你的組件之上。
lass ProfileScreen extends React.Component {
//設置navigation選項 static navigationOptions = { //標題 title: ({ state }) => `${state.params.name}'s Profile!`, //頭部定義了一個右按鈕,來改變edit的狀態 ing或者完成 header: ({ state, setParams }) => ({ // Render a button on the right side of the header // When pressed switches the screen to edit mode. right: ( <Button title={state.params.editing ? 'Done' : 'Edit'} onPress={() => setParams({editing: state.params.editing ? false : true})} /> ), }), }; ...
常用的配置中,主要有以下參數需要注意:
1)visible - bool值,header是否可見。
2)title-標題 String或者是一個react 節點
3)backTitle-返回按鈕在iOS平台上,默認是title的值
4)right- react 節點顯示在header右邊,例如右按鈕
5)left- react 節點顯示在header左邊,例如左按鈕
6)style-header的style
7)titleStyle- header的title的style (^__^) 嘻嘻……
8)tintColor- header的前景色
·cardStack- 配置card stack
react-navigation
說完常見的導航器,我們在看看本文的重點:react-navigation的使用。
首先看一下效果:
1,在項目目錄下,安裝React-navigation庫
npm install --save react-navigation
2,使用StactkNavigator來管理堆棧。暫且命名為HomeScreen.js。默認入口頁面代碼如下:
import React from 'react'; import { AppRegistry, Text, } from 'react-native'; //導入stack導航組件 import { StackNavigator } from 'react-navigation'; class HomeScreen extends React.Component { static navigationOptions = { title: 'Welcome',//標題 }; render() { return <Text>Hello, Navigation!</Text>; } } //導航注冊 const SimpleApp = StackNavigator({ Home: { screen: HomeScreen }, }); AppRegistry.registerComponent('SimpleApp', () => SimpleApp);
運行效果:
3,添加一個新的頁面
class ChatScreen extends React.Component { static navigationOptions = { title: 'Chat with Lucy', }; render() { return ( <View> <Text>Chat with Lucy</Text> </View> ); } }
4,在HomeScreen中添加一個button組件,使用routeName Chat關聯到ChatScreen。
class HomeScreen extends React.Component { static navigationOptions = { title: 'Welcome', }; render() { const { navigate } = this.props.navigation; return ( <View> <Text>Hello, Chat App!</Text> <Button onPress={() => navigate('Chat')} title="Chat with Lucy" /> </View> ); } }
這段代碼主要是給Button綁定onPress事件。這時候,我們使用的兩個跳轉的頁面需要在StackNavigator進行注冊:
const SimpleApp = StackNavigator({ Home: { screen: HomeScreen }, Chat: { screen: ChatScreen },//新添加的頁面 });
所以完整的代碼是:
class HomeScreen extends React.Component { static navigationOptions = { title: 'Welcome',//設置標題內容 }; render() { const { navigate } = this.props.navigation; return ( <View> <Text>Hello, Navigation!</Text> <Button onPress={() => navigate('Chat',{user:'Lucy'})} title="Chat with Lucy"/> </View> ); } } const SimpleApp = StackNavigator({ Home: {screen: HomeScreen}, Chat:{screen:ChatScreen}, });
參數傳遞
在頁面的跳轉過程中,往往會伴隨着參數的傳遞。
navigation參數傳遞
1,在第一個頁面定義參數,將參數傳值給需要傳值的頁面
constructor(props) { super(props); this.state = {}; } ... if(navigator) { navigator.push({ name: 'SecondPageComponent', component: SecondPageComponent, params:{ user:this.state.user, pwd:this.state.pwd } }) }
2,如果需要監聽頁面的state狀態
onChangeText={(text) => this.setState({user: text})}
3,另一個頁面接受參數
componentDidMount() {
//這里獲取從FirstPageComponent傳遞過來的參數: id
this.setState({ user:this.props.user, pwd:this.props.pwd }); }
4,去的傳過來的值:
value={this.state.user }
react-navigation參數傳遞
對於 react-navigation參數的傳遞,使用上比較簡單,只需要在navigate中加一個json格式的對象即可,如:
navigate('Chat', { user: 'Lucy' })
然后在接收的頁面:
class ChatScreen extends React.Component { static navigationOptions = { // Nav options can be defined as a function of the navigation prop: title: ({ state }) => `Chat with ${state.params.user}`, }; render() { // The screen's current route is passed in to `props.navigation.state`: const { params } = this.props.navigation.state; return ( <View> <Text>Chat with {params.user}</Text> </View> ); } }
所以,你就可以看到如下的效果:
TabNavigator
TabNavigator類似於底部導航效果
// 注冊tabs const Tabs = TabNavigator({ Home: { screen: Home, navigationOptions: { // 也可以寫在組件的static navigationOptions內 tabBar: { label: '首頁', icon: ({tintColor}) => (<Image source={require('./app/images/home.png')} style={[{tintColor: tintColor},styles.icon]}/>), }, } }, Bill: { screen: Bill, navigationOptions: { tabBar: { label: '賬單', icon: ({tintColor}) => (<Image source={require('./app/images/bill.png')} style={[{tintColor: tintColor},styles.icon]}/>), }, } }, Me: { screen: Me, navigationOptions: { tabBar: { label: '我', icon: ({tintColor}) => (<Image source={require('./app/images/me.png')} style={[{tintColor: tintColor},styles.icon]}/>), }, } } }, { animationEnabled: false, // 切換頁面時是否有動畫效果 tabBarPosition: 'bottom', // 顯示在底端,android 默認是顯示在頁面頂端的 swipeEnabled: false, // 是否可以左右滑動切換tab backBehavior: 'none', // 按 back 鍵是否跳轉到第一個Tab(首頁), none 為不跳轉 tabBarOptions: { activeTintColor: '#ff8500', // 文字和圖片選中顏色 inactiveTintColor: '#999', // 文字和圖片未選中顏色 showIcon: true, // android 默認不顯示 icon, 需要設置為 true 才會顯示 indicatorStyle: { height: 0 // 如TabBar下面顯示有一條線,可以設高度為0后隱藏 }, style: { backgroundColor: '#fff', // TabBar 背景色 // height: 44 }, labelStyle: { fontSize: 10, // 文字大小 }, }, });
DrawerNavigator
DrawerNavigator類似於抽屜側滑效果。
const DrawerNav = DrawerNavigator({ Home: { screen: Home }, Bill: { screen: Bill }, Me: { screen: Me }, HomeTwo: { screen: HomeTwo }, HomeThree: { screen: HomeThree }, HomeFour: { screen: HomeFour }, BillTwo: { screen: BillTwo }, BillThree: { screen: BillThree } }, { drawerWidth: 200, // 抽屜寬 drawerPosition: 'left', // 抽屜在左邊還是右邊 // contentComponent: CustomDrawerContentComponent, // 自定義抽屜組件 contentOptions: { initialRouteName: Home, // 默認頁面組件 activeTintColor: 'white', // 選中文字顏色 activeBackgroundColor: '#ff8500', // 選中背景顏色 inactiveTintColor: '#666', // 未選中文字顏色 inactiveBackgroundColor: '#fff', // 未選中背景顏色 style: { // 樣式 } } });
iOS版設置
在iOS中使用react-navigation需要注意以下幾點:
使用Xcode設置Schemes;
在AppDelegate添加一下代碼:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { return [RCTLinkingManager application:application openURL:url sourceApplication:sourceApplication annotation:annotation]; }
js組件在注冊路由時設置唯一的路徑path, 例如Home2: { screen: Home2, path:’app/Home2’ };
在手機瀏覽器訪問demo4://app/Home2, 彈窗選擇打開, 就可以打開demo4 app並進到Home2頁面。
react-native-tab-navigator
直接上代碼:
/**
* Sample React Native App
* https://github.com/facebook/react-native * @flow */ import React, { Component } from 'react'; import TabNavigator from 'react-native-tab-navigator'; import { AppRegistry, StyleSheet, Text, Image, View } from 'react-native'; const TabNavigatorItem =TabNavigator.Item; //默認選項 const TAB_HOME_NORMAL=require('./image/tabbar_homepage.png'); const TAB_MINE_NORMAL=require('./image/tabbar_mine.png'); //選中 const TAB_HOME_PRESS=require('./image/tabbar_homepage_selected.png'); const TAB_MINE_PRESS=require('./image/tabbar_mine_selected.png'); export default class HelloWord extends Component { //默認選中 constructor(){ super(); this.state={ selectedTab:'Home', } } //點擊方法 onPress(tabName){ if(tabName){ this.setState({ selectedTab:tabName, } ); } } //渲染選項 renderTabView(title,tabName,tabContent,isBadge){ var tabNomal; var tabPress; switch (tabName) { case 'Home': tabNomal=TAB_HOME_NORMAL; tabPress=TAB_HOME_PRESS; break; case 'Mine': tabNomal=TAB_MINE_NORMAL; tabPress=TAB_MINE_PRESS; break; default: } return( <TabNavigatorItem selected={this.state.selectedTab===tabName} title={title} titleStyle={styles.tabText} selectedTitleStyle={styles.selectedTabText} renderIcon={()=><Image style={styles.icon} source={tabNomal}/>} renderSelectedIcon={()=><Image style={styles.icon} source={tabPress}/>} onPress={()=>this.onPress(tabName)} renderBadge={()=>isBadge?<View style={styles.badgeView}><Text style={styles.badgeText}>15</Text></View>:null} > <View style={styles.page}><Text>{tabContent}</Text></View> </TabNavigatorItem> ); } //自定義TabView tabBarView(){ return ( <TabNavigator tabBarStyle={styles.tab} > {this.renderTabView('首頁','Home','首頁模塊',true)} {this.renderTabView('我的','Mine','我的模塊',false)} </TabNavigator> ); } //渲染界面 render() { var tabView=this.tabBarView(); return ( <View style={styles.container}> {tabView} </View> ); } } const styles = StyleSheet.create({ container: { flex: 1 }, tabText: { fontSize: 10, color: 'black' }, selectedTabText: { fontSize: 10, color: 'green' }, tab:{ height: 52, alignItems:'center', backgroundColor:'#f4f5f6', }, tabIcon:{ width:25, height:25, }, badgeView:{ width:22, height:14 , backgroundColor:'#f85959', borderWidth:1, marginLeft:10, marginTop:3, borderColor:'#FFF', alignItems:'center', justifyContent:'center', borderRadius:8, }, badgeText:{ color:'#fff', fontSize:8, }, icon: { width: 22, height: 22 }, page: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#FFFFFF' }, }); AppRegistry.registerComponent('HelloWord', () => HelloWord);
參考:React Native頁面參數傳遞
https://reactnavigation.org/docs/intro/
引用原文:http://blog.csdn.net/xiangzhihong8/article/details/71249167?ref=myread
寫博客是為了記住自己容易忘記的東西,另外也是對自己工作的總結,文章可以轉載,無需版權。希望盡自己的努力,做到更好,大家一起努力進步!
如果有什么問題,歡迎大家一起探討,代碼如有問題,歡迎各位大神指正!