一起來學習React-Native之react-navigation基本解析

MoMask發表於2019-06-04

前言

  不久前自己也完整開發了一個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完全能勝任這個工作。

 最後,核心程式碼都在上面,我就不貼專案連線了。

 

相關文章