RN路由-React Navigation--Tab navigation

引言

原本打算將React Navigation-Guides這一章內容集中寫在這篇文章內的,但因爲篇幅太長,閱讀的時候很費勁,因此這裏將Guides這一章的內容分篇來記錄。首先,咱們來看看Tab navigation!html

Tab navigation

移動應用中最多見的導航樣式多是基於標籤的導航。 它能夠是屏幕底部的標題,也能夠是標題下方的頂部(甚至代替標題)。react

本指南介紹createBottomTabNavigator。 您也可使用createMaterialBottomTabNavigator和createMaterialTopTabNavigator將選項卡添加到您的應用程序。android

在繼續以前,請先安裝@ react-navigation / bottom-tabs:ios

  • npm
npm install @react-navigation/bottom-tabs
複製代碼
  • yarn
yarn add @react-navigation/bottom-tabs
複製代碼

1 基於標籤的導航的最小示例

import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

function HomeScreen() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Home!</Text>
    </View>
  );
}

function SettingsScreen() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Settings!</Text>
    </View>
  );
}

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}
複製代碼

Try this example on Snackgit

2 自定義外觀

這相似於自定義stack導航器的方式—初始化tab導航器時會設置一些屬性,而其餘屬性則能夠在options中按屏幕自定義。github

// You can import Ionicons from @expo/vector-icons/Ionicons if you use Expo or
// react-native-vector-icons/Ionicons otherwise.
import Ionicons from 'react-native-vector-icons/Ionicons';

// (...)

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        screenOptions={({ route }) => ({
          tabBarIcon: ({ focused, color, size }) => {
            let iconName;

            if (route.name === 'Home') {
              iconName = focused
                ? 'ios-information-circle'
                : 'ios-information-circle-outline';
            } else if (route.name === 'Settings') {
              iconName = focused ? 'ios-list-box' : 'ios-list';
            }

            // You can return any component that you like here!
            return <Ionicons name={iconName} size={size} color={color} />;
          },
        })}
        tabBarOptions={{
          activeTintColor: 'tomato',
          inactiveTintColor: 'gray',
        }}
      >
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}
複製代碼

Try this example on Snacknpm

讓咱們對此進行剖析:redux

  • tabBarIcon是底部標籤導航器中受支持的option。 所以,咱們知道能夠在options prop的屏幕組件上使用它,但在這種狀況下,選擇將其放在Tab.Navigator的screenOptions prop中,以便於集中圖標配置,便於使用。
  • tabBarIcon是一個具備焦點狀態,顏色和大小參數的函數。 若是您進一步瀏覽配置,將會看到tabBarOptions以及activeTintColor和inactiveTintColor。 這些默認值是iOS平臺默認值,可是您能夠在此處更改它們。 傳遞到tabBarIcon的顏色是活動的仍是不活動的,具體取決於聚焦狀態(聚焦爲活動)。 大小是標籤欄指望的圖標大小。
  • 閱讀 full API reference 參考,以獲取有關createBottomTabNavigator配置options的更多信息。

3 icons上添加badge

有時咱們想在某些圖標上添加badge。 一種常見的方法是使用一個額外的視圖容器,並以絕對定位的方式設置badge元素。react-native

function IconWithBadge({ name, badgeCount, color, size }) {
  return (
    <View style={{ width: 24, height: 24, margin: 5 }}>
      <Ionicons name={name} size={size} color={color} />
      {badgeCount > 0 && (
        <View
          style={{
            // On React Native < 0.57 overflow outside of parent will not work on Android, see https://git.io/fhLJ8
            position: 'absolute',
            right: -6,
            top: -3,
            backgroundColor: 'red',
            borderRadius: 6,
            width: 12,
            height: 12,
            justifyContent: 'center',
            alignItems: 'center',
          }}
        >
          <Text style={{ color: 'white', fontSize: 10, fontWeight: 'bold' }}>
            {badgeCount}
          </Text>
        </View>
      )}
    </View>
  );
}
複製代碼

從UI角度來看,該組件已準備就緒,可使用,可是您仍然須要找到某種方法從其餘地方正確傳遞徽章計數,例如使用 React ContextReduxMobX 或 event emitters.markdown

function HomeIconWithBadge(props) {
  // You should pass down the badgeCount in some other ways like React Context API, Redux, MobX or event emitters.
  return <IconWithBadge {...props} badgeCount={3} />;
}
複製代碼

Try this example on Snack 

4 tabs之間跳轉

切換tab使用一樣的API - navigation.navigate。

function HomeScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Home!</Text>
      <Button
        title="Go to Settings"
        onPress={() => navigation.navigate('Settings')}
      />
    </View>
  );
}

function SettingsScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Settings!</Text>
      <Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
    </View>
  );
}
複製代碼

Try this example on Snack

5 每一個tab上的stack導航

一般,tab上不只顯示一個頁面,例如,在您的Twitter feed上,您能夠點擊一條推文,將會跳轉到這個tab裏包含的一個新頁面。 您能夠認爲這是由於每一個tab中都有單獨的導航堆棧,這正是咱們在React Navigation中建模的方式。

import * as React from 'react';
import { Button, Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

function DetailsScreen() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Details!</Text>
    </View>
  );
}

function HomeScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Home screen</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
}

function SettingsScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Settings screen</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
}

const HomeStack = createStackNavigator();

function HomeStackScreen() {
  return (
    <HomeStack.Navigator>
      <HomeStack.Screen name="Home" component={HomeScreen} />
      <HomeStack.Screen name="Details" component={DetailsScreen} />
    </HomeStack.Navigator>
  );
}

const SettingsStack = createStackNavigator();

function SettingsStackScreen() {
  return (
    <SettingsStack.Navigator>
      <SettingsStack.Screen name="Settings" component={SettingsScreen} />
      <SettingsStack.Screen name="Details" component={DetailsScreen} />
    </SettingsStack.Navigator>
  );
}

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeStackScreen} />
        <Tab.Screen name="Settings" component={SettingsStackScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}
複製代碼

Try this example on Snack

6 爲何要用TabNavigator代替TabBarIOS或其餘一些組件

嘗試使用獨立的tab bar組件而不將其集成到您在應用程序中使用的導航庫中是很常見的。在某些狀況下,這很好!可是,應該警告您,這樣作時可能會遇到一些使人沮喪的意外問題。

例如,React Navigation的標籤導航器會爲您處理Android後退按鈕,而獨立組件一般不會。此外,若是您(做爲開發人員)須要爲其調用兩個不一樣的API,則執行諸如「跳至該選項卡,而後轉到此屏幕」之類的操做更加困難。最後,移動用戶界面有許多小的設計細節,要求某些組件知道其餘組件的佈局或存在性-例如,若是您具備半透明的標籤欄,則內容應在其下方滾動,而且滾動視圖應具備插圖在底部等於標籤欄的高度,所以您能夠看到全部內容。雙擊選項卡欄,應使活動導航堆棧彈出到堆棧頂部,再次進行操做應將活動滾動視圖滾動到該堆棧頂部。儘管並不是全部這些行爲均可以經過React Navigation開箱即用地實現,可是若是使用獨立的選項卡視圖組件,它們將是實現的,而且您將不會得到任何這些行爲。

7 tab導航器包含一個stack,想在特定屏幕上隱藏tab bar

See the documentation here

總結

這部份內容主要講的是tab navigation的使用方法,使用這個組件能夠很方便的設置tab導航的結構,也易於擴展和維護,熟悉的朋友應該也有同感!在設置badge上,須要另外去研究一下,後續補充這部份內容。

喜歡的朋友,麻煩點個star哦,謝謝啦~

上一章節:RN路由-React Navigation組件5.x-基本原理(中文文檔)

下一章節:RN路由-React Navigation--Drawer navigation

參考文檔:React Navigation - Tab navigation

相關文章
相關標籤/搜索