前言
不久前自己也完整開發了一個React-Native專案,對其中的一些知識存在疑惑,再加上專案時間比較緊張,來不及做系統的學習。現在來回顧自己開發當中存在的疑惑點,和大家分享。第一篇是關於路由框架react-navigation,當時其實也沒有好好看文件,現在回頭看路由設計的確實比較亂,如果沒看過文件建議直接去看文件,而後再看此篇文章。主要介紹createStackNavigator,createSwitchNavigator,createBottomTabNavigator,createMaterialTopTabNavigator,這四類路由框架,以及他們的組合使用。
createStackNavigator
顧名思義,其實這就是一種基於棧的路由管理方式,棧的特點就是先入後出,最新入棧的介面會顯示在最頂部,這也是Android管理Activity的方式,也是React-Native App開啟頁面最主要的方式。
export function createStackNavigator( routeConfigMap: NavigationRouteConfigMap, stackConfig?: StackNavigatorConfig ): NavigationContainer;
該方法提供兩個引數,一個是NavigationRouteConfigMap,當中儲存的一些你宣告的元件,他們之間構成了一個單獨的路由。還有一個引數是StackNavigatorConfig,它允許你對路由做一個全域性的設定,比如說是否顯示頭部,頭部的主題等等。這邊建議都不顯示頭部,更多的時候,頁面的頭部不盡相同,通過自定的這種形式會對開發更加的友好。需要注意的是,在最新版本的react-navigation當中,必須通過createAppContainer包裹匯出。通過建立js檔案:AppNavigator.js,一個完整的基於createStackNavigator的例子如下:
import { createStackNavigator, createSwitchNavigator, createAppContainer, createBottomTabNavigator, createMaterialTopTabNavigator } from 'react-navigation' import SplashPage from "../page/Splash/SplashPage"; import HomePage from "../page/Home/HomePage"; import Feather from "react-native-vector-icons/Feather" import Page1 from "../page/bottom/Page1"; import Page2 from "../page/bottom/Page2"; import Page3 from "../page/bottom/Page3"; import React from "react"; import Top1 from "../page/top/Top1"; import Top2 from "../page/top/Top2"; import Top3 from "../page/top/Top3"; const InitNavigator = createStackNavigator({ SplashPage: { screen: SplashPage, navigationOptions: { header: null } }, Page1: { screen: Page1, navigationOptions: { header: null } }, Page2: { screen: Page2, navigationOptions: { header: null } }, Page3: { screen: Page3, navigationOptions: { header: null } }, },{ }); export default createAppContainer(InitNavigator);
這個時候我們只需要修改App.js,就可以完成接入路由這個操作了。
import React, {Component} from 'react'; import {Platform, StyleSheet, Text, View, TouchableOpacity} from 'react-native'; import AppNavigator from "./app/navigation/AppNavigator"; type Props = {}; export default class App extends Component<Props> { render() { return ( <AppNavigator/> ); } }
可以看到,單個js檔案中的路由以單個元件的形式提供,可以預見,在專案路由複雜,專案路由多這種情況下react-navigation也一樣可以輕鬆的管理路由。具體的頁面程式碼就不再展示,效果如下:
createSwitchNavigator
switch,意思也比較明顯,就是選擇的意思。也就是說,當你使用這個路由時,記憶體中只會存在一個頁面或者一個路由(多路由情況)。其實,大多數App都有一個歡迎介面,這個介面在App中只會顯示一次,如果單單是使用棧的形式,不好控制出棧的操作,實現起來就比較複雜,那麼我們的createSwitchNavigator就能派上用場了。當跳轉到我們的主路由的時候,歡迎介面也就消失了。來看一下createSwitchNavigator中提供的引數:
export function createSwitchNavigator( routeConfigMap: NavigationRouteConfigMap, switchConfig?: SwitchNavigatorConfig ): NavigationContainer;
可以看到和createStackNavigator大同小意,也是一個路由管理集合,和一個可以對介面的總體設定,那麼要實現我們上面想要的效果如何去做呢?其實也非常簡單,程式碼如下:
import { createStackNavigator, createSwitchNavigator, createAppContainer, createBottomTabNavigator, createMaterialTopTabNavigator } from 'react-navigation' import SplashPage from "../page/Splash/SplashPage"; import HomePage from "../page/Home/HomePage"; import Feather from "react-native-vector-icons/Feather" import Page1 from "../page/bottom/Page1"; import Page2 from "../page/bottom/Page2"; import Page3 from "../page/bottom/Page3"; import React from "react"; import Top1 from "../page/top/Top1"; import Top2 from "../page/top/Top2"; import Top3 from "../page/top/Top3"; const InitNavigator = createStackNavigator({ Page1: { screen: Page1, navigationOptions: { header: null } }, Page2: { screen: Page2, navigationOptions: { header: null } }, Page3: { screen: Page3, navigationOptions: { header: null } }, },{ }); const AppRoot = createSwitchNavigator({ SplashPage: { screen: SplashPage, navigationOptions: { header: null } }, Main: InitNavigator, }); export default createAppContainer(AppRoot);
那麼這個時候,我們的splash介面就不再是跳轉到page1了。而是在AppRoot中的Main了。
import BasePage from "../../base/BasePage"; import {Platform, StyleSheet, Text, View, TouchableOpacity} from 'react-native'; import React, {Component} from 'react'; export default class SplashPage extends BasePage { render() { return ( <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}> <TouchableOpacity onPress={() => { this.goNextPage("Main") }}> <Text>Splash</Text> </TouchableOpacity> </View> ); } }
現在來看下效果
createBottomTabNavigator
如果我們要實現類似微信首頁多tab多介面的時候,createBottomTabNavigator就能派上用場了,他通過單個路由管理多個tab,我們來看一下實現的引數:
export function createBottomTabNavigator( routeConfigMap: NavigationRouteConfigMap, drawConfig?: BottomTabNavigatorConfig ): NavigationContainer;
哎呀,和前面兩個一樣,也是一個路由管理集合,和一個可以對介面的總體設定。具體設定屬性的引數這裡不多說,以後的文章會說到,我們把上面提到的兩個路由結合起來,實現一個大部分App都有的一個正常路由流程。外部是個createSwitchNavigator做splash和主路由,主路由通過createStackNavigator用棧管理,但是第一個page我們使用createBottomTabNavigator做首頁。那麼程式碼如下:
import { createStackNavigator, createSwitchNavigator, createAppContainer, createBottomTabNavigator, createMaterialTopTabNavigator } from 'react-navigation' import SplashPage from "../page/Splash/SplashPage"; import HomePage from "../page/Home/HomePage"; import Feather from "react-native-vector-icons/Feather" import Page1 from "../page/bottom/Page1"; import Page2 from "../page/bottom/Page2"; import Page3 from "../page/bottom/Page3"; import React from "react"; import Top1 from "../page/top/Top1"; import Top2 from "../page/top/Top2"; import Top3 from "../page/top/Top3"; let hotSelest = <Feather name={'activity'} size={26} color='red' />; let hotUnSelest = <Feather name={'activity'} size={26} />; let pointSelect = <Feather name={'thumbs-up'} size={26} color='red' />; let pointUnSelect = <Feather name={'thumbs-up'} size={26} />; let mineSelect = <Feather name={'user'} size={26} color='red' />; let mineUnSelect = <Feather name={'user'} size={26} />; const BottomNavigator = createBottomTabNavigator({ Page1: { screen: Page1, navigationOptions: { tabBarLabel: '最熱', tabBarIcon: ({tinColor, focused}) => (focused ? hotSelest : hotUnSelest) } }, Page2: { screen: Page2, navigationOptions: { tabBarLabel: '點贊', tabBarIcon: ({tinColor, focused}) => (focused ? pointSelect : pointUnSelect) } }, Page3: { screen: Page3, navigationOptions: { tabBarLabel: '我的', tabBarIcon: ({tinColor, focused}) => (focused ? mineSelect : mineUnSelect) } }, }, { tabBarOptions: { activeTintColor: '#e91e63', header: null, } }); const InitNavigator = createStackNavigator({ Page1: { screen: BottomNavigator, navigationOptions: { header: null } }, Top1: { screen: Top1, navigationOptions: { header: null } }, Top2: { screen: Top2, navigationOptions: { header: null } }, },{ }); const AppRoot = createSwitchNavigator({ SplashPage: { screen: SplashPage, navigationOptions: { header: null } }, Main: InitNavigator, }); export default createAppContainer(AppRoot);
通過設定lable,icon兩個屬性,設定圖片和文字,這邊沒有圖片,所以使用了一個三方庫,有興趣的可以瞭解一下。你也可以在,全域性的設定當中設定是否顯示lable和icon和文字選中顏色等等。首頁的第一個介面點選之後會跳轉到top介面,效果如下:
createMaterialTopTabNavigator
同過實現一個material風格的頂部選擇導航,相對於createBottomTabNavigator,有些屬性不同。我們來看看實現方法:
export function createMaterialTopTabNavigator( routeConfigMap: NavigationRouteConfigMap, drawConfig?: TabNavigatorConfig ): NavigationContainer;
也是大同小異,具體的屬性差別實踐之後體會更加深刻,我也會在後面介紹,包括一下高階的用法。我們讓首頁第一個變成materialtop的風格,程式碼也是非常簡單,我們在上面的基礎上修改一下:
import { createStackNavigator, createSwitchNavigator, createAppContainer, createBottomTabNavigator, createMaterialTopTabNavigator } from 'react-navigation' import SplashPage from "../page/Splash/SplashPage"; import HomePage from "../page/Home/HomePage"; import Feather from "react-native-vector-icons/Feather" import Page1 from "../page/bottom/Page1"; import Page2 from "../page/bottom/Page2"; import Page3 from "../page/bottom/Page3"; import React from "react"; import Top1 from "../page/top/Top1"; import Top2 from "../page/top/Top2"; import Top3 from "../page/top/Top3"; const TopNavigator= createMaterialTopTabNavigator({ TopOne:{ screen:Top1 }, TopTwo:{ screen:Top2 }, TopThree:{ screen:Top3 }, }); let hotSelest = <Feather name={'activity'} size={26} color='red' />; let hotUnSelest = <Feather name={'activity'} size={26} />; let pointSelect = <Feather name={'thumbs-up'} size={26} color='red' />; let pointUnSelect = <Feather name={'thumbs-up'} size={26} />; let mineSelect = <Feather name={'user'} size={26} color='red' />; let mineUnSelect = <Feather name={'user'} size={26} />; const BottomNavigator = createBottomTabNavigator({ Page1: { screen: TopNavigator, navigationOptions: { tabBarLabel: '最熱', tabBarIcon: ({tinColor, focused}) => (focused ? hotSelest : hotUnSelest) } }, Page2: { screen: Page2, navigationOptions: { tabBarLabel: '點贊', tabBarIcon: ({tinColor, focused}) => (focused ? pointSelect : pointUnSelect) } }, Page3: { screen: Page3, navigationOptions: { tabBarLabel: '我的', tabBarIcon: ({tinColor, focused}) => (focused ? mineSelect : mineUnSelect) } }, }, { tabBarOptions: { activeTintColor: '#e91e63', header: null, } }); const InitNavigator = createStackNavigator({ Page1: { screen: BottomNavigator, navigationOptions: { header: null } }, Top1: { screen: Top1, navigationOptions: { header: null } }, Top2: { screen: Top2, navigationOptions: { header: null } }, },{ }); const AppRoot = createSwitchNavigator({ SplashPage: { screen: SplashPage, navigationOptions: { header: null } }, Main: InitNavigator, }); export default createAppContainer(AppRoot);
在createBottomTabNavigator的第一個介面,加入了materialtop的路由,來看看效果:
總結
來做一個簡單的總結:
1.這幾種路由無非就是兩個引數,一個是介面的集合以及全域性介面屬性的設定,不同的路由屬性不同,你也可以在單個介面設定他的屬性。
2.路由的使用需要通過createAppContainer包裹,他以一個元件的形式體現在我們的介面上,這也是新版本加上的,無疑讓他更加的靈活。
3.一個完整的App路由絕對不是單個路由那麼簡單的,要好好思考App的業務邏輯,設定出專屬於你的路由,react-navigation完全能勝任這個工作。
最後,核心程式碼都在上面,我就不貼專案連線了。