React Native導航器Navigator
使用導航器可以讓你在應用的不同場景(頁面)間進行切換。導航器通過路由對象來分辨不同的場景。利用renderScene方法,導航欄可以根據指定的路由來渲染場景。可以通過configureScene屬性獲取指定路由對象的配置信息,從而改變場景的動畫或者手勢。——以上內容摘錄自React Native中文網
一、Navigator的屬性
configureScene
可選的函數,用來配置場景動畫和手勢。會帶有兩個參數調用,一個是當前的路由,一個是當前的路由棧。然后它應當返回一個場景配置對象。
使用方式:
(route, routeStack) => Navigator.SceneConfigs.FloatFromRight
切換效果有:
Navigator.SceneConfigs.PushFromRight (默認)
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
initialRoute
類類型的屬性,定義啟動時加載的路由。路由是導航欄用來識別渲染場景的一個對象。initialRoute必須是initialRouteStack中的一個路由。initialRoute默認為initialRouteStack中最后一項。
initialRouteStack
類類型的屬性,用來在Navigator組件初加載時提供導航路徑。如果沒有向Navigator組件提供initialRoute屬性,就必須提供initialRouteStack屬性;如果提供了initialRoute但沒有提供initialRouteStack,那么React Native會生成一個只有initialRoute元素的數據作為initialRouteStack。
navigationBar
該屬性返回一個可以渲染的節點,這個節點可以用作所有界面的通用導航欄。當開發者決定使用navigationBar來進行導航時,大部分應用界面的導航欄都具有相同的格式(相同大小的按鈕、標題欄等),只是按鈕的圖片或者標題欄中的文字各有不同。
給Navigator組件指定導航欄的示例如下:
navigationBar = {
<Navigator.NavigationBar routeMapper={ navigationBarRouteMapper}/>
}
Navigator.NavigationBar是一個可顯示的React Native組件,它必須有一個routeMapper屬性。開發者必須將一個對象指定給routeMapper屬性。這個對象可以有三個成員變量:LeftButton、RightButton、Title。其中,Title成員變量必須有。這三個成員變量要求都是函數類型的,Navigator組件渲染導航欄時,使用這三個函數的返回值渲染導航欄的對應區域。
每個函數可以接收4個參數。示例:
LeftButton: function( route, navigator, index, navState)
在三個成員函數返回的可渲染節點的樣式中設置三個區域的大小。這三個函數返回的可渲染節點就是三個區域中顯示的內容。
不同的頁面需要控制這三個區域中顯示不同的內容,開發者需要將不同頁面待顯示的不同內容(文字、圖片)通過route傳入這三個函數中,然后這三個函數從route的成員變量中去處傳入的供顯示的不同內容,最后渲染顯示。
對按鈕或輸入框的處理,通常都需要調用父組件的函數,這就需要將這個父組件的函數以某種方式傳入routeMapper屬性中。開發者無法直接給routeMapper屬性再傳值,但是可以放在route中,由Natigator組件在渲染時交給routeMapper屬性。而route中的成員變量,都是由開發者提供的,並且對每個事件只能提供一個回調函數,准確地說,是最近一次提供的回調函數會覆蓋上一次提供的回調函數。
Navigator
提供從父導航器獲得的導航器對象。
onDidFocus
每當導航切換完成或初始化之后,調用此回調,參數為新場景的路由。
React native鼓勵開發者使用navigationContext.addListener(‘didfocus’,callback)事件監聽器來實現相同的功能。
onWillFocus
會在導航切換之前調用,參數為目標路由。
React native鼓勵開發者使用navigationContext.addListener(‘willfocus’,callback)事件監聽器來實現相同的功能。
renderScene
必要參數。用來渲染指定路由的場景。調用的參數是路由和導航器。
sceneStyle
指定的樣式將被應用到每一個切換的場景中。
二、導航器的函數
getCurrentRoutes()
獲取當前棧里的路由,也就是push進來,沒有pop掉的那些。
jumpBack()
退回到上一個界面而不卸載當前界面。
jumpForward()
沿界面路徑向前跳一個界面而不卸載當前界面。
jumpTo(route)
跳轉到某個界面而不卸載任何界面。
push(route)
導航組件在路徑列表最前端添加一個新的界面,並馬上跳轉至這個界面。
pop()
導航器退回一個界面並卸載原界面。
replace(route)
用一個新的路由替換掉當前場景。
replaceAtIndex(route, index)
使用一個新的界面替代路徑表中的第index個界面,但不改變當前顯示界面。
replacePrevious(route)
將當前導航路徑的上一個界面使用指定的界面替代。
resetTo(route)
跳轉到新的場景,並且重置整個路由棧。
immediatelyResetRouteStack(routeStack)
使用給定的路徑表替換當前的路徑列表。
popToRoute(route)
導航器回退到指定的界面,並且將這個過程中回退過的界面都卸載。
popToTop()
導航器回退到的第一個場景,卸載掉所有的其他場景。
三、Navigator傳值
實現的效果為:第一個界面向第二個界面傳值,在第二個界面中改變第一個界面的顯示內容。
index.android.js
1 import React from 'react'; 2 import { 3 View, 4 Navigator, 5 AppRegistry 6 } from 'react-native'; 7 import FirstPageComponent from './js/FirstPageComponent'; 8 export default class SampleComponent extends React.Component { 9 render() { 10 let defaultName = 'FirstPageComponent'; 11 let defaultComponent = FirstPageComponent; 12 return ( 13 <Navigator 14 initialRoute={{ name: defaultName, component: defaultComponent }} 15 configureScene={(route) => { 16 return Navigator.SceneConfigs.HorizontalSwipeJumpFromRight; 17 }} 18 renderScene={(route, navigator) => { 19 let Component = route.component; 20 return <Component {...route.params} navigator={navigator} /> 21 }} 22 /> 23 ); 24 } 25 } 26 27 AppRegistry.registerComponent('listen1', () => SampleComponent);
第一個界面
1 import React from 'react'; 2 import { 3 View, 4 Navigator, 5 TouchableOpacity, 6 Text, 7 } from 'react-native'; 8 9 import SecondPageComponent from './SecondPageComponent'; 10 11 export default class FirstPageComponent extends React.Component { 12 13 constructor(props) { 14 super(props); 15 16 this.state = { 17 id: 2, 18 user: null, 19 } 20 } 21 22 23 _pressButton() { 24 let _this = this; 25 const { navigator } = this.props; 26 if(navigator) { 27 navigator.push({ 28 name: 'SecondPageComponent', 29 component: SecondPageComponent, 30 params: { 31 id: this.state.id, 32 //從SecondPageComponent獲取user 33 getUser: function(user) { 34 _this.setState({ 35 user: user 36 }) 37 } 38 } 39 }); 40 } 41 } 42 43 render() { 44 if( this.state.user ) { 45 return( 46 <View> 47 <Text>用戶信息: { JSON.stringify(this.state.user) }</Text> 48 </View> 49 ); 50 }else { 51 return( 52 <View> 53 <TouchableOpacity onPress={this._pressButton.bind(this)}> 54 <Text>查詢ID為{ this.state.id }的用戶信息</Text> 55 </TouchableOpacity> 56 </View> 57 ); 58 } 59 60 } 61 }
第二個界面
1 const USER_MODELS = { 2 1: { name: 'mot', age: 23 }, 3 2: { name: '晴明大大', age: 25 } 4 }; 5 6 import React from 'react'; 7 import { 8 View, 9 Navigator, 10 TouchableOpacity, 11 Text, 12 } from 'react-native'; 13 14 import FirstPageComponent from './FirstPageComponent'; 15 16 export default class SecondPageComponent extends React.Component { 17 18 constructor(props) { 19 super(props); 20 this.state = { 21 id: null 22 } 23 } 24 25 componentDidMount() { 26 //這里獲取從FirstPageComponent傳遞過來的參數: id 27 this.setState({ 28 id: this.props.id 29 }); 30 } 31 32 _pressButton() { 33 const { navigator } = this.props; 34 35 if(this.props.getUser) { 36 let user = USER_MODELS[this.props.id]; 37 this.props.getUser(user); 38 } 39 40 if(navigator) { 41 navigator.pop(); 42 } 43 } 44 45 render() { 46 return( 47 <View> 48 <Text>獲得的參數: id={ this.state.id }</Text> 49 <TouchableOpacity onPress={this._pressButton.bind(this)}> 50 <Text>點我跳回去</Text> 51 </TouchableOpacity> 52 </View> 53 ); 54 } 55 }
在第二個界面中修改第一個界面的原理是:在第一個界面中聲明一個方法,可以更改其state。我們知道,state發生改變,界面就會重新渲染。在傳值的時候,將該方法作為一個屬性傳給第二個界面。在第二個界面中執行該方法,就重新渲染了第一個界面。只不過此時的第一界面沒有在屏幕上。當第二個界面卸載(pop)后,返回第一個界面,就看到了更改后的第一個界面。
