React Navigation實現界面導航與跳轉


React Native--使用React Navigation實現界面導航與跳轉

        在瀏覽器中我們可以通過<a>標簽與url實現不同頁面之間的跳轉,利用瀏覽器的返回按鈕返回之前瀏覽的頁面,但是在React Native中卻沒有集成內嵌的全局棧來實現這個界面的跳轉,因此需要使用第三方庫來實現這個功能。React Navigation就是這樣一個源於ReactNative社區的用於實現界面導航的js庫。通過如下方法安裝react navigation到你的項目中:

yarn add react-navigation
# 或者通過npm安裝:
# npm install --save react-navigation

        React Navigation常用有三個組件,其中StackNavigator用於實現頁面跳轉,TabNavigation用於標簽頁之間切換,DrawerNavigation用於實現抽屜式側邊欄。使用前需要先引入組件:

import {DrawerNavigator,TabNavigator,StackNavigator} from 'react-navigation'

1、StackNavigator

        StackNavigator組件用於實現在不同的頁面之間的跳轉,並且對頁面歷史進行管理,就像瀏覽器那樣,用一個棧保存瀏覽頁面。當你打開一個新頁面時,將頁面壓入棧頂,當你需要返回時,從棧頂彈出頁面。不同的是,通過React Navigation可以在移動設備上獲得更加真實的用戶體驗,比如利用屏幕手勢操作,以及更加逼真的動畫切換效果。

 1.1、定義路由

        總體上看StackNavigator()接收兩個參數,分別是需要跳轉管理的路由模塊以及Navigator的基本設置,返回一個React Component組件。因此可以將你的所有頁面作為路由模塊放在StackNavigator中形成根路由RootStack,然后將其作為ReactNative的入口導出。

        在每個路由模塊中通過screen關鍵字定義對應渲染的ReactNative組件

const RootStack = StackNavigator(
  {//定義路由
Home: {                       //定義Home對應HomeScreen組件
screen: HomeScreen,
},
Details: {
      screen: DetailsScreen,
},
},
{//定義配置
initialRouteName: 'Home',     //設置初始路由為Home
}
);
export default class App extends Component {
  render() {                            //將Navigation作為根路徑導出
return <RootStack />;
}
}

        嵌套路由:由於StackNavigator返回一個React組件,因此它也可以作為子組件添加到另一個StackNavigator路由中,形成層疊路由結構。例如Home Screen與DetailScreen構成MainStack,MainStack與ModalScreen構成RootStack:

     

1.2、路由跳轉

        StackNavigator會為每個注冊的路由組件傳遞參數navigation屬性,通過this.props.navigationnavigate方法可以實現頁面間的跳轉,其參數為StackNavigator中已定義的路由,例如從主頁跳轉到詳情頁Details:

<Button title='跳轉到詳情' onPress={()=>this.props.navigation.navigate('Details')} />

        返回:每個界面的頭部導航欄左邊默認設置了一個返回按鈕,通過它可以返回到之前一個頁面,如果你希望手動觸發返回,可以調用this.props.navigation.goBack()

        路由跳轉實際上就是新打開一個頁面並將路由壓入一個棧中,點擊返回時,從棧頂彈出一個頁面。與瀏覽器不同的是,當給navigate傳遞的參數是本頁面時,它依舊會壓入棧內,點擊返回時會彈出本頁面,而瀏覽器會辨別這是本頁面,不會再壓入棧頂。

1.3、參數傳遞

        當頁面跳轉時,可以把需要傳遞的數據作為參數放在navigate方法的第二個參數中,例如:

<Button title='跳轉到詳情'
onPress={()=>this.props.navigation.navigate('Details',{
          userName:'Tory',
userInfo:'Hello'
})}
/>
        在路由頁面內,通過 this.props.navigation.state.params可以得到上一個頁面傳入的參數,例如在Details頁面獲取上面的數據:
class DetailsScreen extends Component {
  render() {
    const data=this.props.navigation.state.params;
return (
      <View style={styles.container}>
        <Text>你好,{data.userName}!</Text>
      </View>
);
}
}

1.4、導航欄設置

       通過對組件內的靜態常量 navigationOptions可以對組件的導航欄進行設置。
    1.4.1、設置與修改

        靜態對象:navigationOptions可以直接接收一個對象,例如設置詳情頁導航欄的標題

class DetailsScreen extends Component {
  static navigationOptions = {
    title: '詳情頁'
};
}
     函數返回:由於上面通過static設置的靜態常量,它不是組件的一個實例,無法通過this.props訪問到navigation.state.params。但如果通過函數的方式返回navigationOptions對象,React Navigation在調用函數時會函數默認傳入參數props,就可以拿到params。例如:
static navigationOptions=((props)=>{
  return {
    title:props.navigation.state.params.title
  }
});

        修改navigationOptions:通過this.props.navigation.setParams()方法可以對params進行修改,例如修改標題:

<Button title='修改標題'
onPress={()=>{
          this.props.navigation.setParams({title:'修改后的標題'})
        }}
/>
    1.4.2、navigationOptions屬性
static navigationOptions={
  title:'詳情頁',
header:HeaderComponent,                       //自定義頭部組件
headerTitle:TitleComponent,                   //自定義標題組件
headerLeft:LeftComponent,                     //自定義左邊組件,會替換掉默認返回按鈕
headerRight:<Text>右邊元素</Text>,            //自定義右邊元素,注意這里不可以放組件
headerBackImage:{uri:'mipmap/ic_launcher'},   //自定義返回按鈕的圖片
headerStyle:{                                 //導航欄樣式設置
backgroundColor:'#8bc9ff',
},
headerTintColor:'#fff',                       //按鈕、標題顏色設置
headerTitleStyle:{                            //標題字體樣式設置
fontWeight:'bold',
},
headerTransparent:true,                       //使頭部背景透明
gesturesEnabled:true,                         //開啟手勢操作
gestureDirection:'inverted',            //修改返回手勢操作方向為從右到左,默認為從左到右
gestureResponseDistance:{               //定義手勢響應距離屏幕邊界的距離
horizontal:100,
vertical:50
}
};

       如果在組件內部定義navigationOptions,它只會對當前頁面起作用,如果希望對所有組件設置通用options,可以把navigationOptions對象放在前面的1.1提到的路由定義中。頁面內的navigationOptions比通用設置具有更高的優先級。

        注意自定義組件返回的是JSX元素,而不是React Component類。

const RootStack = StackNavigator(
  {//定義路由
Home: {screen: HomeScreen},
Details:{screen: DetailsScreen},
},
{//定義配置
initialRouteName: 'Home',     navigationOptions:{           //導航欄通用設置
headerStyle:{
        backgroundColor:'#7276ff'
}
    }
  }
);

1.5、頭部與組件通信

        在navigationOptions中設置的組件無法通過this訪問到頁面組件DetailsScreen,如果希望二者之間進行通信,則需要借助navigation.params。例如:

class DetailsScreen extends React.Component {
  state={count:0};
static navigationOptions = (props) => {
    const params = props.navigation.state.params;
return {
      headerRight: (                        //通過params為按鈕綁定increase方法
<Button onPress={params.increase} title="+1" />
),
};
};
componentWillMount() {                    //通過setParams將increase方法綁定到_increase
this.props.navigation.setParams({ increase: this._increase });
}
  _increase=()=>{                           //設置state.count+1
this.setState(preState=>{return {count:preState.count+1}});
};
render() {
    return (
      <View style={styles.container}>
        <Text>計數為:{this.state.count}</Text>
      </View>
);
}
}
        在navigationOptions中的<Button>想要修改DetailsScreen的state.count,是無法通過this的,需要先給按鈕綁定params.increase方法,然后在組件掛載前通過setParams將increase綁定到DetailsScree的內部方法this._increase,才可以訪問修改state.count。

2、TabNavigator

       React Navigation提供了TabNavigator來實現不同標簽頁之間的跳轉。安卓的標簽欄默認顯示在頭部,IOS在底部。

2.1、定義路由組件

        同StackNavigator一樣,使用TabNavigator首先需要定義每個路由頁面以及其對應的組件,Tabnavigator方法的第一個參數就是所有標簽頁的路由,第二個為設置選項,最后返回一個React Component,因此可以把它返回當作index.js的入口

//默認導出TabNavigator組件給index.js
export default TabNavigator (
  {
    Home:{screen:HomeScreen},       //標簽頁Home對應HomeScreen組件
Message:{screen:MessageScreen}
  },
{
    //TabNavigator的設置
}
)

 

//index.js中引入TabNavigator並定義為入口
import { AppRegistry } from 'react-native';
import TabNavigator from './TabNavigation';

AppRegistry.registerComponent('Navigation', () => TabNavigator);

        TabNavigator可以與StackNavigator嵌套使用,比如進入App后有兩個標簽頁Home與Message,點擊Home中的按鈕從Home跳轉到詳情頁Detail,因此HomeScreen與DetailScreen通過StackNavigator構成了一個HomeStack,然后與MessageScreen一起又構成了TabNavigator:

const HomeStack=StackNavigator(
  {
    Home:{screen:HomeScreen},
Detail:{screen:DetailScreen}
  }
);
export default TabNavigator (
  {
    Home:{screen:HomeStack},       //標簽頁Home對應HomeScreen組件
Message:{screen:MessageScreen}
  }
)

2.2、TabNavigator的設置

   在 TabNavigator()的第二個參數可以對標簽欄進行詳細的配置
export default TabNavigator (
  {
    Home:{screen:HomeStack},       //標簽頁Home對應HomeScreen組件
Message:{screen:MessageScreen}
  },
{
    tabBarComponent: TabBarBottom,        //自定義標簽欄組件
tabBarPosition: 'bottom',             //設置標簽欄位置
animationEnabled: true,               //開啟標簽頁切換動畫
swipeEnabled: true,                   //允許標簽頁之間滑動切換
initialRouteName:'Home',              //初始路由
tabBarOptions:{                       //標簽欄的樣式設置如下↓
style:{                               //整體標簽欄樣式設置
backgroundColor:'#49a9ff',
},
tabStyle:{                            //每個標簽的樣式
width:150
},
labelStyle:{                          //標簽文字樣式
fontSize:16
},
iconStyle:{                           //標簽圖標樣式
width:20,
},
activeTintColor:'blue',               //標簽激活時的前景色
activeBackgroundColor:'white',        //標簽激活時的背景色
inactiveTintColor:'white',            //標簽未激活時的前景色
inactiveBackgroundColor:'blue',       //標簽未激活時的背景色
pressColor:'#9dbbff',                 //標簽被點擊時的顏色(僅安卓)
showLabel:false,                     //將文字標簽隱藏,默認為true開啟
showIcon:true,                       //顯示圖標,默認為false隱藏
}
  }
)

    在每個路由可以分別通過navigationOptions對tabBar標簽進行其他設置:

 

Find:{
  screen:FindScreen,                        //定義路由對應的組件
navigationOptions:{
    title:'消息',                          //設置標題
tabBarVisible:false,                  //隱藏標簽欄,默認為true顯示
swipeEnabled:true,                    //是否允許滑動切換標簽頁,默認接收TabNavigator中的設置
tabBarIcon:(tab)=>renderIcon(tab,'message'),           //定義渲染Icon的方法
tabBarLabel:'消息頁',             //定義標簽文字或者渲染方法,如不設置默認渲染title
tabBarOnPress:(obj)=>tapTab(obj)                       //標簽被點擊時觸發的方法
}
},

    渲染標簽的icon:首先需要在之前的TabNavigator()設置中開啟顯示icon,之后通過tabBarIcon屬性對應的方法來渲染icon,默認傳入參數{ focused: boolean, tintColor: string }(我將它命名為tab),其中focused表示當前標簽是否被選中,tintColor為前景色。我定義了renderIcon方法來實現Icon的渲染,並傳入另外一個參數component代表不同組件,用於匹配對應的icon,例如當傳入'message'且未激活時,iconSrc為'tabbar_message':

function renderIcon(tab,component){
  console.log('ictest');
let iconSrc='';
if (tab.focused){                       //標簽激活狀態下icon的路徑
iconSrc=component+'_highlighted';
}else{                                  //未激活狀態下的icon
iconSrc='tabbar_'+component;
}
  return <Image source={{uri:'mipmap/'+iconSrc}} style={{width:30,height:30}} />
}
    標簽頁跳轉: 除了通過左右滑動切換標簽頁之外,還可以通過 this.props.navigation.navigate('組件名')手動跳轉。

3、DrawerNavigator

       DrawerNavigator用於實現屏幕側邊欄拉出的導航效果,效果如下:

    

3.1、定義路由組件

   在DrawerNavigator的各個路由之間實現跳轉,首先需要定義路由組件,其路由定義方式同以上兩種導航方式相同。DrawerNavigator()方法接收兩個參數,第一個為路由組件,第二個為參數設置,之后返回一個React組件,將它暴露給index.js,作為程序的默認入口。

3.2、打開側邊欄

        除了通過在屏幕邊緣滑動外,還可以通過函數手動打開側邊欄:

this.props.navigation.navigate('DrawerOpen'); // 打開側邊欄
this.props.navigation.navigate('DrawerClose'); // 關閉側邊欄
this.props.navigation.navigate('DrawerToggle');//切換側邊欄打開/關閉

 

3.3、DrawerNavigator個性化設置

    在其構造方法的第二個參數可以對組件進行一些常用的設置如下:

export default DrawerNavigator(
  {
    Home: {  screen: HomeScreen },
Notifications: { screen: NotificationsScreen },
},
{
    drawerWidth:200,            //側邊欄的寬度
drawerPosition:'right',     //定義側邊欄位置右邊,默認left左邊
contentComponent:CustomDrawer,            //自定義側邊欄組件
drawerBackgroundColor:'#c8eaff',          //側邊欄背景色
contentOptions:{                          //對側邊欄中的標簽詳細設置如下↓
activeTintColor:'#936eff',                 //標簽激活時的前景色
activeBackgroundColor:'#8fc3ff',           //標簽激活時的背景色
inactiveTintColor:'#598dff',               //標簽未激活時的前景色
inactiveBackgroundColor:'#c1e1ff',         //標簽未激活時的背景色
itemsContainerStyle:{                      //側邊欄整體樣式
borderTopWidth:2,borderTopColor:'#5153ff'
},
itemStyle:{                                //單個標簽樣式
borderBottomWidth:2,borderBottomColor:'#41a6ff'
},
labelStyle:{                               //標簽文字樣式
fontSize:16
},
iconContainerStyle:styles.icon,            //標簽icon樣式
}
  }
);

 

        在每個組件內對側邊欄標簽的label、icon進行設置:

class HomeScreen extends React.Component {
  static navigationOptions = {
    drawerLabel: '主頁',                          //設置標簽label文字
drawerIcon: ({focused, tintColor}) => (       //設置標簽的icon
<Image
source={{uri: 'mipmap/tabbar_home'}}
        style={[styles.icon, {tintColor: tintColor}]}
      />
),
};
}

 

3.4、自定義側邊欄 

通過上面的contentComponent來自定義DrawerNavigator組件為CustomDrawer:

 

class CustomDrawer extends Component{
  constructor(props){
    super(props);                       //通過super傳入上層調用的props
}
  render(){
    return (
      <ScrollView>
        <SafeAreaView style={styles.container} forceInset={{ top: 'always', horizontal: 'never' }}>
{/*自定義區域*/}
          <View style={{flex:1,alignItems:'center'}}>
            <Image source={{uri:'mipmap/user_icon'}} style={styles.userPic} />
          </View>
          <DrawerItems {...this.props} />
        </SafeAreaView>
      </ScrollView>
);
}
}

 

        其中<SafeAreaView><DrawerItems>組件需要引入:

import {DrawerItems, SafeAreaView} from 'react-navigation'

 

        把自定義的側邊欄內容放在<SafeAreaView>中。

        如果希望保留導航標簽可以通過<DrawerItem>繪制出標簽列表,其中傳入props參數數組,並用操作符"..."展開。

 

代碼的GitHub鏈接如下:

https://github.com/SuperTory/ReactNativeNavigation

 

---------------------
作者:theVicTory
來源:CSDN
原文:https://blog.csdn.net/theVicTory/article/details/80059632
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM