移動端有個常用的UI控件導航控制器,在RN裏面就是Navigator控件。今天在說Navigator之前先說個不是很恰當的比喻用來解釋Navigator的工作流程:平時在看電視的時候我們都會用遙控器切換電視機播放的頻道,在遙控器上面你不僅可以使用上一個、下一個這種按鍵來切換頻道也可以手動輸入頻道數來跳轉到指定的頻道,在我看來這個過程就是使用navigator進行頁面跳轉的過程。至於你跳轉到指定頻道後電視機播放的內容那是由這個頻道接收到的電磁波包含的信息決定的,指定頻道接收的電磁波可以類比指定頁面綁定的路由,頁面將顯示什麼內容都是根據route這個路由對象包含的內容決定的。接下來看看演示的效果:
我們先定義一組路由信息:
const routes = [
{message:'第一頁',index:0,component:FirstPage},
{message:'第二頁',index:1,component:SecondPage},
{message:'第三頁',index:2,component:ThirdPage}
];
routes裏面的每個元素就是一個路由,這個路由裏面包含了頁面顯示所需要的信息,message我們規定它代表了頁面的標題,index我們將所有的頁面編號用於識別,component我們規定它表示了這個頁面將要展示的具體內容。注意,路由裏面包含的信息都是可以自己定義的。
Navigator裏面有一些常用的屬性:
initialRoute 這個屬性可以用來指定初始化頁面,你可以傳入一個路由用來初始化。
initialRouteStack 這個屬性可以傳入一個路由數組來表示將要顯示的一系列頁面,設置了這個後Navigator會將這些路由都一次性的壓入堆棧。
renderScene當前渲染的頁面,它的參數是一個函數,簡單看下官方的說明
在renderScene這個屬性裏面我們可以很方便的獲取到兩個主要的值:
route和navigator,這樣我們就可以顯示我們想要的任何內容了也可以跳轉的其他頁面離開當前頁面了
/**
* Required function which renders the scene for a given route. Will be
* invoked with the `route` and the `navigator` object.
*
* ```
* (route, navigator) =>
* <MySceneComponent title={route.title} navigator={navigator} />
* ```
*/
renderScene: PropTypes.func.isRequired,
style 是navigator的樣式
configureScene這個屬性是用來配置頁面跳轉動畫和手勢的,常用的動畫手勢如下
- Navigator.SceneConfigs.PushFromRight (default)
- Navigator.SceneConfigs.FloatFromRight
- Navigator.SceneConfigs.FloatFromLeft
- Navigator.SceneConfigs.FloatFromBottom
- Navigator.SceneConfigs.FloatFromBottomAndroid
- Navigator.SceneConfigs.FadeAndroid
- Navigator.SceneConfigs.HorizontalSwipeJump
- Navigator.SceneConfigs.HorizontalSwipeJumpFromRight
- Navigator.SceneConfigs.VerticalUpSwipeJump
- Navigator.SceneConfigs.VerticalDownSwipeJump
navigationBar 這個屬性是用來設置導航欄的,我們可以設置導航欄的左右按鈕和標題,接下來我們看看部分代碼:
return(
<Navigator
initialRoute={routes[0]}
initialRouteStack = {routes}
renderScene={(route,navigator) =>
<route.component route={route} navigator={navigator} routes={routes}/>
}
style={styles.navigator}
configureScene = {(route) => {
if (route.index === 0) {
return Navigator.SceneConfigs.HorizontalSwipeJump
}
if (route.index === 1) {
return Navigator.SceneConfigs.PushFromRight
}
if (route.index === 2) {
return Navigator.SceneConfigs.FloatFromBottom
}
}}
navigationBar={
<Navigator.NavigationBar
routeMapper={{
LeftButton: (route, navigator, index, navState) =>
{
if(route.index === 0) {
return null;
}else {
return(
<TouchableHighlight onPress={() => {
navigator.jumpBack() //不能是當前棧裏面的第一個頁面
}}>
<Text>back</Text>
</TouchableHighlight>
)
}
},
RightButton: (route, navigator, index, navState) =>
{
if(route.index === 2) {
return null;
}else {
return(
<TouchableHighlight onPress={() => {
let routes = navigator.getCurrentRoutes()
if (routes.length < 1) {
return;
}
if (routes.pop().index !== route.index) {
navigator.jumpForward() //不能是當前棧裏面的最後一個頁面
}
}}>
<Text>forward</Text>
</TouchableHighlight>)
}
},
Title: (route, navigator, index, navState) =>
{ return (<Text style={styles.Title}>{route.message}</Text>); },
}}
style={{backgroundColor: 'green'}}
/>
}
>
</Navigator>
)
上面的導航欄的左右按鈕分別是返回到上一個頁面和跳轉到下一個頁面,要注意的是這裏的跳轉都是在路由棧裏的路由間跳轉的,所以在執行navigator.jumpForward()之前要判斷當前頁面不能是棧裏面的最後一個頁面,在執行navigator.jumpBack() 之前也要判斷當前頁面不能是棧裏面的第一個頁面。
下面我們簡單介紹第二個頁面,其他兩個跟第二個頁面類似:
class SecondPage extends Component {
render () {
return(
<View style={{backgroundColor:'burlywood',flex:1}}>
<TouchableHighlight
onPress={() => {
this.props.navigator.push(this.props.routes[this.props.route.index+1])
}
}>
<Text style={[styles.text,{fontSize:15}]}>第二頁push</Text>
</TouchableHighlight>
<TouchableHighlight
onPress={() => {
this.props.navigator.pop()
}
}>
<Text style={[styles.text,{fontSize:15}]}>第二頁pop</Text>
</TouchableHighlight>
</View>
)
}
}
在每個頁面裏面我們都可以獲取到navigator、route這兩個關鍵信息,這樣我們就可以隨意在當前頁面跳轉到指定的頁面了。在這裏要注意的是pop() push()這一組跳轉動作和jumpBack() jumpForward()這一組跳轉動作的區別在於前一組的跳轉會改變路由棧 後一組不會。
以上代碼都已經上傳gitub ,源碼下載