react-navigation圖文攻略

小綠和小藍發表於2019-01-15

接觸react-native有一段時間了,感覺學習最大的難點就是 rn的國內資料不多,老外寫的文件看起來不舒服

其中在react-navigation上面花了很長的時間,搞的心力憔悴,但是看國內的文章,很多都是2.x版本的,api不向下相容,各種報錯物件不存在,前期天天踩坑

react-navigation圖文攻略

後來看了很長時間的官方文件,才搞清楚react-navigation的使用

所以在我感覺我現在已經踩過很多坑的情況下,我決定寫這篇文章,來幫助rn開發者儘可能的跳過react-navigation的一些坑

本人使用react-native的一些練習程式碼github

react-native官網

react-navigation官網

本文章基於 "react-navigation": "^3.0.9" 假如版本跨度比較大,本文可能就不適合了

另外,學習庫或者外掛最好的方式就官方閱讀文件(感覺有點打臉自己)

安裝

儘量不要看百度出來的文章,,例如**dn,比較陳舊,已經不是個當前版本,一定要看文件

rn專案裡面,我推薦使用yarn, npm有時候會出現依賴不全的問題

在已經初始化完成,並且確保可以執行的rn專案裡面,輸入一下命令

yarn add react-navigation
yarn add react-native-gesture-handler
react-native link react-native-gesture-handler
複製程式碼

在已經搭建好的專案裡面,執行上面的命令,這都是必須的,詳情請看文件React navigation安裝

安裝完成後啟動專案(啟動無報錯即意味著navigation安裝成功了)

導航器

沒有接觸過原生開發的web開發者看到這些很react風格的導航器名稱,一定很陌生,沒關係,後面圖示

rn上的導航器的編寫就是類似 前端的路由的編寫,通過rn的導航器來決定App的路由結構,以及個性化的頁面

  • createStackNavigator 最基本的頁面 自帶上方導航欄

    為你的應用程式提供一種在每個新螢幕放置在堆疊頂部的螢幕之間轉換的方法。

  • createBottomTabNavigator

    頁面底部的標籤欄,可讓您在不同路由之間進行切換。 路由被懶載入 - 它們的螢幕元件只有在第一次獲取焦點時才會被載入。

  • createMaterialBottomTabNavigator

    功能上和 createBottomTabNavigator 一樣,這個更加個性化,但是我們可以基於createBottomTabNavigator自定義任意底部導航欄

    螢幕底部的材料設計主題標籤欄,可讓您在不同路由之間切換。 路由被懶載入 - 它們的螢幕元件直到第一次獲取焦點時才被載入。

  • createMaterialTopTabNavigator

    螢幕頂部左右滑動切換tab

    螢幕頂部的材料設計主題標籤欄, 可通過點選路線或水平滑動來切換不同的路由。 預設情況下, 轉換是動態的。 每個路由的螢幕元件將立即安裝。

  • createDrawerNavigator: 抽屜效果導航器,由側邊劃出;

  • createSwitchNavigator:

    createSwitchNavigator 的用途是一次只顯示一個頁面。 預設情況下,它不處理返回操作,並在你切換時將路由重置為預設狀態。(特定場合才會使用)

常用的導航器就這麼多,下面將一一介紹給大家

使用vscode開發一些必備的外掛

工欲善其事,必先利其器,好的開發環境可以有效地加速開發速度,以及開發體驗感

使用vscode開發,推薦安裝Full React/React Native/React Router/Redux/GraphQL/ES7/Testing/PropTypes snippets

react-navigation圖文攻略

另外開發react推薦外掛

React Native Snippet

React Native Tools

Reactjs code snippets

以上外掛安裝完成後,就基本滿足使用vscode進行react native的開發了 :wink:

安裝好的專案我們稍微改造一下,

one.js two.js three.js 是頁面 隨便寫點什麼就好

navigation資料夾內部進行導航器的管理

react-navigation圖文攻略

createStackNavigator

這個是最常見的一個導航器,大部分頁面都是通過他進行配置的,使用起來也很簡單

先看看官方說明

react-navigation圖文攻略

現在我們在navigation/index.js進行路由的配置

import { createStackNavigator, createAppContainer } from 'react-navigation'
import One from '../pages/One'
import Two from '../pages/Two'
import Three from '../pages/Three'

const Stack = createStackNavigator({
  One: {
    screen: One
  },
  Two: {
    screen: Two
  },
  Three: {
    screen: Three
  }
})

export default createAppContainer(Stack)
// createAppContainer是 react-navigation 的app容器,並將頂層的 navigator 連結到整個應用環境(後面再說)
複製程式碼

現在我們需要在根節點匯出這個導航器配置,所以需要修改根目錄的App.js

import React, { Component } from 'react'
import Navigation from './app/navigation'

export default class App extends Component {
  render() {
    return <Navigation />
  }
}
複製程式碼

這個我們就匯出導航器配置,接下來重啟專案

react-navigation圖文攻略

成功了!

但是目前還不能進行頁面之前的切換,react-navigation提供了導航器之前的切換功能

關於切換路由 react-navigation 提供了很多api,下圖是最基礎的一部分

react-navigation圖文攻略

還記得前面建立容器的API createAppContainer嗎

他在props裡面提供了navigation物件,用於進行導航器切換

在One.js裡面新增切導航器的程式碼One.js

import React, { Component } from 'react'
import { Text, View, Button } from 'react-native'

export default class One extends Component {
  render() {
    return (
      <View>
        <Text> One </Text>
        <Button
          title="跳轉到Two頁面"
          onPress={() => {
            this.props.navigation.navigate('Two')
          }}
        />
      </View>
    )
  }
}
複製程式碼

react-navigation圖文攻略

原生的感覺真的棒~

我們不僅可以切換頁面,還可以像原生一樣配置頁面,react-navigation提供了大量的導航的自定義配置

例如

我們可以新增頁面標題,ios與android,導航欄會自適應

我們可以任意的選擇顯示或者不顯示導航欄

設定導航欄顏色 等等你可以想到的個性化設定

更新naviigation/index.js

import { createStackNavigator, createAppContainer } from 'react-navigation'
import One from '../pages/One'
import Two from '../pages/Two'
import Three from '../pages/Three'

const Stack = createStackNavigator({
  One: {
    screen: One,
    navigationOptions: {
      title: 'One'
    }
  },
  Two: {
    screen: Two,
    navigationOptions: {
      title: 'Two',
      headerStyle: {
        backgroundColor: '#f4511e',
      },
      headerTintColor: '#fff',
      headerTitleStyle: {
        fontWeight: 'bold',
      },
    }
  },
  Three: {
    screen: Three,
    navigationOptions: {
      title: 'Three'
    }
  }
},{

})

export default createAppContainer(Stack)
複製程式碼

react-navigation圖文攻略

更多的navigationOptions的配置請看官方文件的

配置標題欄

導航選項

導航器內部螢幕的選項

createBottomTabNavigator

大部分的移動端專案都有底部導航欄,得益於單頁應用,webapp更多的出現在原生端那麼在react-native上,如何建立一個底部導航欄呢?

react-navigation圖文攻略

從web的角度理解 就是 通過底部導航欄進行元件的懶載入切換

讓我們根據官方文件建立一個導航欄試試

修改navigation/index.js

import {
  createStackNavigator,
  createBottomTabNavigator,
  createAppContainer
} from 'react-navigation'
import One from '../pages/One'
import Two from '../pages/Two'
import Three from '../pages/Three'
const BottomBar = createBottomTabNavigator(
  {
    One: {
      screen: One,
      navigationOptions: {
        title: 'One'
      }
    },
    Two: {
      screen: Two,
      navigationOptions: {
        title: 'Two'
      }
    },
    Three: {
      screen: Three,
      navigationOptions: {
        title: 'Three'
      }
    }
  },
  {
    initialRouteName: 'One' // 初始化頁面
  }
)
const Stack = createStackNavigator({
  BottomBar: {
    screen: BottomBar,
    navigationOptions: {
      header: null
    }
  }
})

export default createAppContainer(Stack)
複製程式碼

我們引入了createBottomTabNavigatorcreateBottomTabNavigator裡面加了3個頁面,最後將匯出的底部導航器物件再加入到createStackNavigator中,作為普通頁面的形式

react-navigation圖文攻略

基礎的底部導航器實現了~

在基礎API上面,我們可以做很多自定義的操作,自定義圖示自定義文字,等等,具體請看文件

下面我們給我們的導航欄加一個圖示,讓他看起來更加美觀

在專案裡面新增幾個小icon(圖片用的是iconfont上面的)

react-navigation圖文攻略

react-navigation圖文攻略

網路上9成的文章都說明了在rn專案裡面使用 react-native-vector-icons 這個圖示庫進行圖示的新增 我這裡使用不常見的方案,使用本地png圖片作為底部icon,當然這個使用在具體專案裡面應該封裝起來,這樣類小程式的模式,我相信可以很好的幫助理解,以下編碼方式僅供學習

修改navigation/index.js

import React from 'react'
import { Image } from 'react-native'
import {
  createStackNavigator,
  createBottomTabNavigator,
  createAppContainer
} from 'react-navigation'

import One from '../pages/One'
import Two from '../pages/Two'
import Three from '../pages/Three'
const BottomBar = createBottomTabNavigator(
  {
    One: {
      screen: One,
      navigationOptions: {
        title: 'One',
        tabBarIcon: ({ tintColor }) => {
          let sourceImg
          if (tintColor == '#1296db') {
            sourceImg = require('../image/one-active.png')
          } else {
            sourceImg = require('../image/one.png')
          }
          return (
          <Image
            source={sourceImg}
            style={{ width: 24, height: 24 }}
            color={tintColor}
          />
        )}
      }
    },
    Two: {
      screen: Two,
      navigationOptions: {
        title: 'Two',
        tabBarIcon: ({ tintColor }) => {
          console.log(tintColor);
          let sourceImg
          if (tintColor == '#1296db') {
            sourceImg = require('../image/my-active.png')
          } else {
            sourceImg = require('../image/my.png')
          }
          return (
          <Image
            source={sourceImg}
            style={{ width: 24, height: 24 }}
            color={tintColor}
          />
        )}
      }
    },
    Three: {
      screen: Three,
      navigationOptions: {
        title: 'Three',
        tabBarIcon: ({ tintColor }) => {
          let sourceImg
          if (tintColor == '#1296db') {
            sourceImg = require('../image/message-active.png')
          } else {
            sourceImg = require('../image/message.png')
          }
          return (
          <Image
            source={sourceImg}
            style={{ width: 24, height: 24 }}
            color={tintColor}
          />
        )}
      }
    }
  },
  {
    initialRouteName: 'One', // 初始化頁面
    tabBarOptions: {
      activeTintColor: '#1296db',
      inactiveTintColor: 'black'
    }
  }
)
const Stack = createStackNavigator({
  BottomBar: {
    screen: BottomBar,
    navigationOptions: {
      header: null
    }
  }
})

export default createAppContainer(Stack)
複製程式碼

react-navigation圖文攻略

reactnavigation的導航欄只能做這些嗎?當然不是,可以通過指定tabBarComponent,來自定義你的導航欄元件,這個比較複雜,我後期會寫一篇文章出來詳細說明

createMaterialBottomTabNavigator

這個給人一種開箱即用的感覺,至於專案當中具體選擇什麼,這個要看需求

react-navigation圖文攻略

文件明確指出,需要安裝以下庫

yarn add react-navigation-material-bottom-tabs react-native-paper react-native-vector-icons
react-native link react-native-vector-icons
複製程式碼

我們來實現一下官方案例的效果

修改navigation/index.js

import React from 'react'
import {
  createStackNavigator,
  createAppContainer
} from 'react-navigation'
import { createMaterialBottomTabNavigator } from 'react-navigation-material-bottom-tabs'
import Ionicons from 'react-native-vector-icons/Ionicons'
import One from '../pages/One'
import Two from '../pages/Two'
import Three from '../pages/Three'

const BottomMater = createMaterialBottomTabNavigator(
  {
    One: {
      screen: One,
      navigationOptions: {
        tabBarColor: '#3472EE', // 頁面背景色
        tabBarIcon: ({ tintColor }) => (
          <Ionicons name="ios-home" color={tintColor} size={24} />
        )
      }
    },
    Two: {
      screen: Two,
      navigationOptions: {
        tabBarColor: '#EC3E3E',
        tabBarIcon: ({ tintColor }) => (
          <Ionicons name="ios-options" color={tintColor} size={24} />
        )
      }
    },
    Three: {
      screen: Three,
      navigationOptions: {
        tabBarColor: '#0EA748',
        tabBarIcon: ({ tintColor }) => (
          <Ionicons name="ios-chatbubbles" color={tintColor} size={24} />
        )
      }
    }
  },
  {
    initialRouteName: 'One',
    activeColor: 'white',
    inactiveColor: 'gray',
    shifting: true
  }
)

const Stack = createStackNavigator({
  BottomMater: {
    screen: BottomMater,
    navigationOptions: {
      header: null
    }
  }
})

export default createAppContainer(Stack)

複製程式碼

react-navigation圖文攻略

這樣類似的效果,react-navitation都可以完成,發揮你的想象力?

關於底部導航器的配置很多,沒辦法通過一篇文章一一介紹,詳情請看官方文件

createMaterialTopTabNavigator

螢幕頂部的標籤欄, 可通過點選路線或水平滑動來切換不同的路由。 預設情況下, 轉換是動態的。 每個路由的螢幕元件將立即安裝。

可以看一下我之前模擬拼多多的頁面(當時是做技術驗證)

react-navigation圖文攻略

就這樣的效果

下面我們可以根據文件在我們的demo專案裡面自己實現一下這樣的效果

新增兩個頁面 Four.js Five.js 隨便寫點什麼就行

為了更加合理設定邏輯,我將TopBar的所有導航器配置程式碼放到一個檔案當中

navigation資料夾內新建檔案TopBar.js

import { createMaterialTopTabNavigator } from 'react-navigation'
import One from '../pages/One'
import Four from '../pages/Four'
import Five from '../pages/Five'

export default createMaterialTopTabNavigator(
  {
    One: {
      screen: One, // 配置頁面
      navigationOptions: {
        tabBarLabel: 'One'
      }
    },
    Four: {
      screen: Four,
      navigationOptions: {
        tabBarLabel: 'Four'
      }
    },
    Five: {
      screen: Five,
      navigationOptions: {
        tabBarLabel: 'Five'
      }
    }
  },
  {
    initialRouteName: 'One',
    lazy: true,
    tabBarOptions: {
      scrollEnabled: true,
      upperCaseLabel: false, // 是否大寫
      activeTintColor: 'red', // 活動選項卡
      inactiveTintColor: 'red', // "非活動" 選項卡
      tabStyle: {
        // 選項卡樣式
        // width: 60,
        // paddingTop: 35,
        paddingBottom: 4
      },
      style: {
        backgroundColor: 'white' // 頭部導航欄樣式
      },
      indicatorStyle: {
        backgroundColor: 'red' // 指示器樣式
      }
    }
  }
)

複製程式碼

最後修改navigation/index.js,將我們新建的頂部導航器匯入

import React from 'react'
import { Image } from 'react-native'
import {
  createStackNavigator,
  createBottomTabNavigator,
  createAppContainer
} from 'react-navigation'
import { createMaterialBottomTabNavigator } from 'react-navigation-material-bottom-tabs'
import Ionicons from 'react-native-vector-icons/Ionicons'
import TopBar from './TopBar'
import Two from '../pages/Two'
import Three from '../pages/Three'

const BottomMater = createMaterialBottomTabNavigator(
  {
    TopBar: {
      screen: TopBar,
      navigationOptions: {
        tabBarColor: '#3472EE', // 頁面背景色
        tabBarIcon: ({ tintColor }) => (
          <Ionicons name="ios-home" color={tintColor} size={24} />
        )
      }
    },
    Two: {
      screen: Two,
      navigationOptions: {
        tabBarColor: '#EC3E3E',
        tabBarIcon: ({ tintColor }) => (
          <Ionicons name="ios-options" color={tintColor} size={24} />
        )
      }
    },
    Three: {
      screen: Three,
      navigationOptions: {
        tabBarColor: '#0EA748',
        tabBarIcon: ({ tintColor }) => (
          <Ionicons name="ios-chatbubbles" color={tintColor} size={24} />
        )
      }
    }
  },
  {
    initialRouteName: 'TopBar',
    activeColor: 'white',
    inactiveColor: 'gray',
    shifting: true
  }
)

const Stack = createStackNavigator({
  BottomMater: {
    screen: BottomMater,
    navigationOptions: {
      header: null
    }
  }
})

export default createAppContainer(Stack)

複製程式碼

react-navigation圖文攻略

是不是很簡單,或者所,是不是學會了react-navigation的套路了 ~

到這裡多聯絡,多理解,基本可以完成一般專案的搭建了,

你也可以看看我寫過的其他文章,或者一些react-native的倉庫程式碼,

定位 訊息推送 APP啟動屏 第三方整合 RN配置全面屏 都得到了比較好的解決

RN相關文章

React-Native專案中使用Redux

React-Native使用極光進行訊息推送

RN打包android APK檔案

React Native樣式的另類寫法.md

React-Native 回到頂部.md

React-native可能遇到的問題

關於createDrawerNavigator(抽屜元件) 和 createSwitchNavigator(僅顯示一次頁面),放到後面再說~

相關文章