在 React Native
中,官方已經推薦使用 react-navigation
來實現各個界面的跳轉和不同板塊的切換。 react-navigation
主要包括三個組件:
StackNavigator
導航組件TabNavigator
切換組件DrawerNavigator
抽屜組件
StackNavigator
用於實現各個頁面之間的跳轉, TabNavigator
用來實現同一個頁面上不同界面的切換, DrawerNavigator
可以實現側滑的抽屜效果。
StackNavigator
StackNavigator
組件采用堆棧式的頁面導航來實現各個界面跳轉。它的構造函數:
StackNavigator(RouteConfigs, StackNavigatorConfig)
有 RouteConfigs
和 StackNavigatorConfig
兩個參數。
RouteConfigs
RouteConfigs
參數表示各個頁面路由配置,類似於android原生開發中的 AndroidManifest.xml
,它是讓導航器知道需要導航的路由對應的頁面。
const RouteConfigs = { Home: { screen: HomePage, navigationOptions: ({navigation}) => ({ title: '首頁', }), }, Find: { screen: FindPage, navigationOptions: ({navigation}) => ({ title: '發現', }), }, Mine: { screen: MinePage, navigationOptions: ({navigation}) => ({ title: '我的', }), }, };
這里給導航器配置了三個頁面, Home
、 Find
、 Mine
為路由名稱, screen
屬性值 HomePage
、 FindPage
、 MinePage
為對應路由的頁面。
navigationOptions
為對應路由頁面的配置選項:
title - 可以作為頭部標題 headerTitle ,或者Tab標題 tabBarLabel header - 自定義的頭部組件,使用該屬性后系統的頭部組件會消失 headerTitle - 頭部的標題,即頁面的標題 headerBackTitle - 返回標題,默認為 title headerTruncatedBackTitle - 返回標題不能顯示時(比如返回標題太長了)顯示此標題,默認為 “Back” headerRight - 頭部右邊組件 headerLeft - 頭部左邊組件 headerStyle - 頭部組件的樣式 headerTitleStyle - 頭部標題的樣式 headerBackTitleStyle - 頭部返回標題的樣式 headerTintColor - 頭部顏色 headerPressColorAndroid - Android 5.0 以上MD風格的波紋顏色 gesturesEnabled - 否能側滑返回, iOS 默認 true , Android 默認 false
StackNavigatorConfig
StackNavigatorConfig
參數表示導航器的配置,包括導航器的初始頁面、各個頁面之間導航的動畫、頁面的配置選項等等:
const StackNavigatorConfig = { initialRouteName: 'Home', initialRouteParams: {initPara: '初始頁面參數'}, navigationOptions: { title: '標題', headerTitleStyle: {fontSize: 18, color: '#666666'}, headerStyle: {height: 48, backgroundColor: '#fff'}, }, paths: 'page/main', mode: 'card', headerMode: 'screen', cardStyle: {backgroundColor: "#ffffff"}, transitionConfig: (() => ({ screenInterpolator: CardStackStyleInterpolator.forHorizontal, })), onTransitionStart: (() => { console.log('頁面跳轉動畫開始'); }), onTransitionEnd: (() => { console.log('頁面跳轉動畫結束'); }), }; initialRouteName - 導航器組件中初始顯示頁面的路由名稱,如果不設置,則默認第一個路由頁面為初始顯示頁面 initialRouteParams - 給初始路由的參數,在初始顯示的頁面中可以通過 this.props.navigation.state.params 來獲取 navigationOptions - 路由頁面的配置選項,它會被 RouteConfigs 參數中的 navigationOptions 的對應屬性覆蓋。 paths - 路由中設置的路徑的覆蓋映射配置 mode - 頁面跳轉方式,有 card 和 modal 兩種,默認為 card : card - 原生系統默認的的跳轉 modal - 只針對iOS平台,模態跳轉 headerMode - 頁面跳轉時,頭部的動畫模式,有 float 、 screen 、 none 三種: float - 漸變,類似iOS的原生效果 screen - 標題與屏幕一起淡入淡出 none - 沒有動畫 cardStyle - 為各個頁面設置統一的樣式,比如背景色,字體大小等 transitionConfig - 配置頁面跳轉的動畫,覆蓋默認的動畫效果 onTransitionStart - 頁面跳轉動畫即將開始時調用 onTransitionEnd - 頁面跳轉動畫一旦完成會馬上調用
頁面的配置選項 navigationOptions
通常還可以在對應頁面中去靜態配置,比如在 HomePage
頁面中:
export default class HomePage extends Component { // 配置頁面導航選項 static navigationOptions = ({navigation}) => ({ title: 'HOME', titleStyle: {color: '#ff00ff'}, headerStyle:{backgroundColor:'#000000'} }); render() { return ( <View></View> ) }; }
同樣地,在頁面里面采用靜態的方式配置 navigationOptions
中的屬性,會覆蓋 StackNavigator
構造函數中兩個參數 RouteConfigs
和 StackNavigatorConfig
配置的 navigationOptions
里面的對應屬性。 navigationOptions
中屬性的優先級是:
頁面中靜態配置 > RouteConfigs
> StackNavigatorConfig
有了 RouteConfigs
和 StackNavigatorConfig
兩個參數,就可以構造出一個導航器組件 StackNavigator
,直接引用該組件:
const Navigator = StackNavigator(RouteConfigs, StackNavigatorConfig); export default class MainComponent extends Component { render() { return ( <Navigator/> ) }; }
已經配置好導航器以及對應的路由頁面了,但是要完成頁面之間的跳轉,還需要 navigation
。
navigation
在導航器中的每一個頁面,都有 navigation
屬性,該屬性有以下幾個屬性/方法:
navigate - 跳轉到其他頁面 state - 當前頁面導航器的狀態 setParams - 更改路由的參數 goBack - 返回 dispatch - 發送一個action
navigete
調用這個方法可以跳轉到導航器中的其他頁面,此方法有三個參數:
— routeName 導航器中配置的路由名稱 — params 傳遞參數到下一個頁面 — action action 比如: this.props.navigation.navigate('Find', {param: 'i am the param'});
state
state
里面包含有傳遞過來的參數 params
、 key
、路由名稱 routeName
,打印log可以看得到:
{ params: { param: 'i am the param' }, key: 'id-1500546317301-1', routeName: 'Mine' }
setParams
更改當前頁面路由的參數,比如可以用來更新頭部的按鈕或者標題。
componentDidMount() { this.props.navigation.setParams({param:'i am the new param'}) }
goBack
回退,可以不傳,也可以傳參數,還可以傳 null
。
this.props.navigation.goBack(); // 回退到上一個頁面 this.props.navigation.goBack(null); // 回退到任意一個頁面 this.props.navigation.goBack('Home'); // 回退到Home頁面
TabNavigator
TabNavigator
,即是Tab選項卡,類似於原生 android
中的 TabLayout
,它的構造函數:
TabNavigator(RouteConfigs, TabNavigatorConfig)
api和 StackNavigator
類似,參數 RouteConfigs
是路由配置,參數 TabNavigatorConfig
是Tab選項卡配置。
RouteConfigs
路由配置和 StackNavigator
中是一樣的,配置路由以及對應的 screen
頁面, navigationOptions
為對應路由頁面的配置選項:
title - Tab標題,可用作 headerTitle 和 tabBarLabel 回退標題 tabBarVisible - Tab的是否可見,沒有設置的話默認為 true tabBarIcon - Tab的icon組件,可以根據 {focused: boolean, tintColor: string} 方法來返回一個icon組件 tabBarLabel - Tab中顯示的標題字符串或者組件,也可以根據 { focused: boolean, tintColor: string } 方法返回一個組件
TabNavigatorConfig
tabBarComponent - Tab選項卡組件,有 TabBarBottom 和 TabBarTop 兩個值,在iOS中默認為 TabBarBottom ,在Android中默認為 TabBarTop 。 TabBarTop - 在頁面的頂部 TabBarBottom - 在頁面的底部 tabBarPosition - Tab選項卡的位置,有 top 或 bottom 兩個值 swipeEnabled - 是否可以滑動切換Tab選項卡 animationEnabled - 點擊Tab選項卡切換界面是否需要動畫 lazy - 是否懶加載頁面 initialRouteName - 初始顯示的Tab對應的頁面路由名稱 order - 用路由名稱數組來表示Tab選項卡的順序,默認為路由配置順序 paths - 路徑配置 backBehavior - androd點擊返回鍵時的處理,有 initialRoute 和 none 兩個值 initailRoute - 返回初始界面 none - 退出 tabBarOptions - Tab配置屬性,用在 TabBarTop 和 TabBarBottom 時有些屬性不一致: 用於 TabBarTop 時: activeTintColor - 選中的文字顏色 inactiveTintColor - 未選中的文字顏色 showIcon - 是否顯示圖標,默認顯示 showLabel - 是否顯示標簽,默認顯示 upperCaseLabel - 是否使用大寫字母,默認使用 pressColor - android 5.0以上的MD風格波紋顏色 pressOpacity - android 5.0以下或者iOS按下的透明度 scrollEnabled - 是否可以滾動 tabStyle - 單個Tab的樣式 indicatorStyle - 指示器的樣式 labelStyle - 標簽的樣式 iconStyle - icon的樣式 style - 整個TabBar的樣式 用於 TabBarBottom 時: activeTintColor - 選中Tab的文字顏色 activeBackgroundColor - 選中Tab的背景顏色 inactiveTintColor - 未選中Tab的的文字顏色 inactiveBackgroundColor - 未選中Tab的背景顏色 showLabel - 是否顯示標題,默認顯示 style - 整個TabBar的樣式 labelStyle - 標簽的樣式 tabStyle - 單個Tab的樣式
底部Tab導航示例
import React, {Component} from 'react'; import {StackNavigator, TabBarBottom, TabNavigator} from "react-navigation"; import HomeScreen from "./index18/HomeScreen"; import NearByScreen from "./index18/NearByScreen"; import MineScreen from "./index18/MineScreen"; import TabBarItem from "./index18/TabBarItem"; export default class MainComponent extends Component { render() { return ( <Navigator/> ); } } const TabRouteConfigs = { Home: { screen: HomeScreen, navigationOptions: ({navigation}) => ({ tabBarLabel: '首頁', tabBarIcon: ({focused, tintColor}) => ( <TabBarItem tintColor={tintColor} focused={focused} normalImage={require('./img/tabbar/pfb_tabbar_homepage_2x.png')} selectedImage={require('./img/tabbar/pfb_tabbar_homepage_selected_2x.png')} /> ), }), }, NearBy: { screen: NearByScreen, navigationOptions: { tabBarLabel: '附近', tabBarIcon: ({focused, tintColor}) => ( <TabBarItem tintColor={tintColor} focused={focused} normalImage={require('./img/tabbar/pfb_tabbar_merchant_2x.png')} selectedImage={require('./img/tabbar/pfb_tabbar_merchant_selected_2x.png')} /> ), }, } , Mine: { screen: MineScreen, navigationOptions: { tabBarLabel: '我的', tabBarIcon: ({focused, tintColor}) => ( <TabBarItem tintColor={tintColor} focused={focused} normalImage={require('./img/tabbar/pfb_tabbar_mine_2x.png')} selectedImage={require('./img/tabbar/pfb_tabbar_mine_selected_2x.png')} /> ), }, } }; const TabNavigatorConfigs = { initialRouteName: 'Home', tabBarComponent: TabBarBottom, tabBarPosition: 'bottom', lazy: true, }; const Tab = TabNavigator(TabRouteConfigs, TabNavigatorConfigs); const StackRouteConfigs = { Tab: { screen: Tab, } }; const StackNavigatorConfigs = { initialRouteName: 'Tab', navigationOptions: { title: '標題', headerStyle: {backgroundColor: '#5da8ff'}, headerTitleStyle: {color: '#333333'}, } }; const Navigator = StackNavigator(StackRouteConfigs, StackNavigatorConfigs);
頂部Tab選項卡示例
import React, {Component} from "react"; import {StackNavigator, TabBarTop, TabNavigator} from "react-navigation"; import HomeScreen from "./index18/HomeScreen"; import NearByScreen from "./index18/NearByScreen"; import MineScreen from "./index18/MineScreen"; export default class MainComponent extends Component { render() { return ( <Navigator/> ); } } const TabRouteConfigs = { Home: { screen: HomeScreen, navigationOptions: ({navigation}) => ({ tabBarLabel: '首頁', }), }, NearBy: { screen: NearByScreen, navigationOptions: { tabBarLabel: '附近', }, } , Mine: { screen: MineScreen, navigationOptions: { tabBarLabel: '我的', }, } }; const TabNavigatorConfigs = { initialRouteName: 'Home', tabBarComponent: TabBarTop, tabBarPosition: 'top', lazy: true, tabBarOptions: {} }; const Tab = TabNavigator(TabRouteConfigs, TabNavigatorConfigs); const StackRouteConfigs = { Tab: { screen: Tab, } }; const StackNavigatorConfigs = { initialRouteName: 'Tab', navigationOptions: { title: '標題', headerStyle: {backgroundColor: '#5da8ff'}, headerTitleStyle: {color: '#333333'}, } }; const Navigator = StackNavigator(StackRouteConfigs, StackNavigatorConfigs);
DrawerNavigator
在原生Android MD 風格里面很多app都會采用側滑抽屜來做主頁面的導航,利用 DrawerNavigator
在RN中可以很方便來實現抽屜導航.
DrawerNavigator(RouteConfigs, DrawerNavigatorConfig)
和 DrawerNavigator
的構造函數一樣,參數配置也類似。
RouteConfigs
抽屜導航的路由配置 RouteConfigs
,和 TabNavigator
的路由配置完全一樣, screen
配置對應路由頁面, navigationOptions
為對應頁面的抽屜配置選項:
title
- 抽屜標題,和headerTitle
、drawerLabel
一樣drawerLabel
- 標簽字符串,或者自定義組件, 可以根據{ focused: boolean, tintColor: string }
函數來返回一個自定義組件作為標簽drawerIcon
- 抽屜icon,可以根據{ focused: boolean, tintColor: string }
函數來返回一個自定義組件作為icon
DrawerNavigatorConfig
抽屜配置項屬性:
drawerWidth - 抽屜寬度,可以使用Dimensions獲取屏幕的寬度,動態計算 drawerPosition - 抽屜位置,可以是 left 或者 right contentComponent - 抽屜內容組件,可以自定義側滑抽屜中的所有內容,默認為 DrawerItems contentOptions - 用來配置抽屜內容的屬性。當用來配置 DrawerItems 是配置屬性選項: items - 抽屜欄目的路由名稱數組,可以被修改 activeItemKey - 當前選中頁面的key id activeTintColor - 選中條目狀態的文字顏色 activeBackgroundColor - 選中條目的背景色 inactiveTintColor - 未選中條目狀態的文字顏色 inactiveBackgroundColor - 未選中條目的背景色 onItemPress(route) - 條目按下時會調用此方法 style - 抽屜內容的樣式 labelStyle - 抽屜的條目標題/標簽樣式 initialRouteName - 初始化展示的頁面路由名稱 order - 抽屜導航欄目順序,用路由名稱數組表示 paths - 路徑 backBehavior - androd點擊返回鍵時的處理,有initialRoute和none兩個值, initailRoute:返回初始界面, none :退出
抽屜導航示例
import React, {Component} from 'react'; import {DrawerNavigator, StackNavigator, TabBarBottom, TabNavigator} from "react-navigation"; import HomeScreen from "./index18/HomeScreen"; import NearByScreen from "./index18/NearByScreen"; import MineScreen from "./index18/MineScreen"; import TabBarItem from "./index18/TabBarItem"; export default class MainComponent extends Component { render() { return ( <Navigator/> ); } } const DrawerRouteConfigs = { Home: { screen: HomeScreen, navigationOptions: ({navigation}) => ({ drawerLabel : '首頁', drawerIcon : ({focused, tintColor}) => ( <TabBarItem tintColor={tintColor} focused={focused} normalImage={require('./img/tabbar/pfb_tabbar_homepage_2x.png')} selectedImage={require('./img/tabbar/pfb_tabbar_homepage_selected_2x.png')} /> ), }), }, NearBy: { screen: NearByScreen, navigationOptions: { drawerLabel : '附近', drawerIcon : ({focused, tintColor}) => ( <TabBarItem tintColor={tintColor} focused={focused} normalImage={require('./img/tabbar/pfb_tabbar_merchant_2x.png')} selectedImage={require('./img/tabbar/pfb_tabbar_merchant_selected_2x.png')} /> ), }, }, Mine: { screen: MineScreen, navigationOptions: { drawerLabel : '我的', drawerIcon : ({focused, tintColor}) => ( <TabBarItem tintColor={tintColor} focused={focused} normalImage={require('./img/tabbar/pfb_tabbar_mine_2x.png')} selectedImage={require('./img/tabbar/pfb_tabbar_mine_selected_2x.png')} /> ), }, } }; const DrawerNavigatorConfigs = { initialRouteName: 'Home', tabBarComponent: TabBarBottom, tabBarPosition: 'bottom', lazy: true, tabBarOptions: {} }; const Drawer = DrawerNavigator(DrawerRouteConfigs, DrawerNavigatorConfigs); const StackRouteConfigs = { Drawer: { screen: Drawer, } }; const StackNavigatorConfigs = { initialRouteName: 'Drawer', navigationOptions: { title: '標題', headerStyle: {backgroundColor: '#5da8ff'}, headerTitleStyle: {color: '#333333'}, } }; const Navigator = StackNavigator(StackRouteConfigs, StackNavigatorConfigs);
源碼: https://git.oschina.net/xiaojianjun/DD (index20.js、index21.js、index22.js)