在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://gitee.com/xiaojianjun/DD.git (index20.js、index21.js、index22.js)
參考
https://reactnavigation.org/docs/
ReactNative導航新寵兒react-navigation