React Native —— react-navigation的使用

React Native中,官方已經推薦使用react-navigation來實現各個界面的跳轉和不同板塊的切換。react-navigation主要包括三個組件:

  • StackNavigator 導航組件
  • TabNavigator 切換組件
  • DrawerNavigator 抽屜組件

StackNavigator用于實現各個頁面之間的跳轉,TabNavigator用來實現同一個頁面上不同界面的切換,DrawerNavigator 可以實現側滑的抽屜效果。

StackNavigator

StackNavigator組件采用堆棧式的頁面導航來實現各個界面跳轉。它的構造函數:

StackNavigator(RouteConfigs, StackNavigatorConfig)

RouteConfigsStackNavigatorConfig兩個參數。

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: '我的',
        }),
    },
};

這里給導航器配置了三個頁面,HomeFindMine為路由名稱,screen屬性值HomePageFindPageMinePage為對應路由的頁面。

navigationOptions為對應路由頁面的配置選項:

  • title - 可以作為頭部標題headerTitle,或者Tab標題tabBarLabel
  • header - 自定義的頭部組件,使用該屬性后系統的頭部組件會消失
  • headerTitle - 頭部的標題,即頁面的標題
  • headerBackTitle - 返回標題,默認為title
  • headerTruncatedBackTitle - 返回標題不能顯示時(比如返回標題太長了)顯示此標題,默認為“Back”
  • headerRight - 頭部右邊組件
  • headerLeft - 頭部左邊組件
  • headerStyle - 頭部組件的樣式
  • headerTitleStyle - 頭部標題的樣式
  • headerBackTitleStyle - 頭部返回標題的樣式
  • headerTintColor - 頭部顏色
  • headerPressColorAndroid - Android 5.0以上MD風格的波紋顏色
  • gesturesEnabled - 否能側滑返回,iOS默認trueAndroid默認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 - 頁面跳轉方式,有cardmodal兩種,默認為card
    • card - 原生系統默認的的跳轉
    • modal - 只針對iOS平臺,模態跳轉
  • headerMode - 頁面跳轉時,頭部的動畫模式,有floatscreennone三種:
    • 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構造函數中兩個參數RouteConfigsStackNavigatorConfig配置的navigationOptions里面的對應屬性。navigationOptions中屬性的優先級是:
頁面中靜態配置 > RouteConfigs > StackNavigatorConfig

有了RouteConfigsStackNavigatorConfig兩個參數,就可以構造出一個導航器組件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里面包含有傳遞過來的參數paramskey、路由名稱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標題,可用作headerTitletabBarLabel回退標題
  • tabBarVisible - Tab的是否可見,沒有設置的話默認為true
  • tabBarIcon - Tab的icon組件,可以根據{focused: boolean, tintColor: string}方法來返回一個icon組件
  • tabBarLabel - Tab中顯示的標題字符串或者組件,也可以根據{ focused: boolean, tintColor: string }方法返回一個組件
TabNavigatorConfig
  • tabBarComponent - Tab選項卡組件,有TabBarBottomTabBarTop兩個值,在iOS中默認為TabBarBottom,在Android中默認為TabBarTop
    • TabBarTop - 在頁面的頂部
    • TabBarBottom - 在頁面的底部
  • tabBarPosition - Tab選項卡的位置,有 topbottom兩個值
  • swipeEnabled - 是否可以滑動切換Tab選項卡
  • animationEnabled - 點擊Tab選項卡切換界面是否需要動畫
  • lazy - 是否懶加載頁面
  • initialRouteName - 初始顯示的Tab對應的頁面路由名稱
  • order - 用路由名稱數組來表示Tab選項卡的順序,默認為路由配置順序
  • paths - 路徑配置
  • backBehavior - androd點擊返回鍵時的處理,有initialRoutenone兩個值
    • initailRoute - 返回初始界面
    • none - 退出
  • tabBarOptions - Tab配置屬性,用在TabBarTopTabBarBottom時有些屬性不一致:
    • 用于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 - 抽屜標題,和headerTitledrawerLabel一樣
  • 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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374

推薦閱讀更多精彩內容