RN路由-React Navigation--Tab navigation

引言

本来打算将React Navigation-Guides这一章内容集中写在这篇文章内的,但由于篇幅太长,阅读的时候很费劲,所以这里将Guides这一章的内容分篇来记录。首先,我们来看看Tab navigation!

Tab navigation

移动应用中最常见的导航样式可能是基于标签的导航。 它可以是屏幕底部的标题,也可以是标题下方的顶部(甚至代替标题)。

本指南介绍createBottomTabNavigator。 您也可以使用createMaterialBottomTabNavigator和createMaterialTopTabNavigator将选项卡添加到您的应用程序。

在继续之前,请先安装@ react-navigation / bottom-tabs:

  • 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 Snack

2 自定义外观

这类似于自定义stack导航器的方式—初始化tab导航器时会设置一些属性,而其他属性则可以在options中按屏幕自定义。

// 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 Snack

让我们对此进行剖析:

  • tabBarIcon是底部标签导航器中受支持的option。 因此,我们知道可以在options prop的屏幕组件上使用它,但在这种情况下,选择将其放在Tab.Navigator的screenOptions prop中,以便于集中图标配置,便于使用。
  • tabBarIcon是一个具有焦点状态,颜色和大小参数的函数。 如果您进一步浏览配置,将会看到tabBarOptions以及activeTintColor和inactiveTintColor。 这些默认值是iOS平台默认值,但是您可以在此处更改它们。 传递到tabBarIcon的颜色是活动的还是不活动的,具体取决于聚焦状态(聚焦为活动)。 大小是标签栏期望的图标大小。
  • 阅读 full API reference 参考,以获取有关createBottomTabNavigator配置options的更多信息。

3 icons上添加badge

有时我们想在某些图标上添加badge。 一种常见的方法是使用一个额外的视图容器,并以绝对定位的方式设置badge元素。

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 Context, Redux, MobXevent emitters.

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354