ProComponents, templates & AI tooling
2.3k

Tabs 标签页

使用选项卡视图组织内容,支持动画过渡与指示器。

导入

import { Tabs } from 'heroui-native';

结构

<Tabs>
  <Tabs.List>
    <Tabs.ScrollView>
      <Tabs.Indicator />
      <Tabs.Trigger>
        <Tabs.Label>...</Tabs.Label>
      </Tabs.Trigger>
      <Tabs.Separator />
      <Tabs.Trigger>
        <Tabs.Label>...</Tabs.Label>
      </Tabs.Trigger>
    </Tabs.ScrollView>
  </Tabs.List>
  <Tabs.Content>...</Tabs.Content>
</Tabs>
  • Tabs:管理选项卡状态与选中的根容器。控制当前激活项、处理值变化,并向子组件提供上下文。
  • Tabs.List:放置选项卡触发器的容器。将多个触发器组合在一起,并支持 primarysecondary 等样式变体。
  • Tabs.ScrollView:可选的横向滚动容器。当标签溢出时可横向滚动,并可在选中时自动居中。
  • Tabs.Trigger:每个选项卡的交互触发器。处理按压以切换激活项,并测量位置以驱动指示器动画。
  • Tabs.Label:触发器上的文字标签,用于展示选项卡标题及对应样式。
  • Tabs.Indicator:当前激活项的可视指示器,可在选项卡之间以弹簧或时长动画平滑过渡。
  • Tabs.Separator:选项卡之间的分隔线。当当前值不在 betweenValues 数组中时显示,并带有透明度过渡动画。
  • Tabs.Content:面板内容容器。当其 value 与当前激活项一致时显示对应内容。

用法

基础用法

Tabs 使用复合子组件,将内容划分为可切换的区域。

<Tabs defaultValue="tab1">
  <Tabs.List>
    <Tabs.Indicator />
    <Tabs.Trigger value="tab1">
      <Tabs.Label>标签一</Tabs.Label>
    </Tabs.Trigger>
    <Tabs.Trigger value="tab2">
      <Tabs.Label>标签二</Tabs.Label>
    </Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="tab1">...</Tabs.Content>
  <Tabs.Content value="tab2">...</Tabs.Content>
</Tabs>

主样式(primary)

默认圆角主样式,选中项背后为填充指示器。

<Tabs value={activeTab} onValueChange={setActiveTab} variant="primary">
  <Tabs.List>
    <Tabs.Indicator />
    <Tabs.Trigger value="settings">
      <Tabs.Label>设置</Tabs.Label>
    </Tabs.Trigger>
    <Tabs.Trigger value="profile">
      <Tabs.Label>个人资料</Tabs.Label>
    </Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="settings">...</Tabs.Content>
  <Tabs.Content value="profile">...</Tabs.Content>
</Tabs>

次样式(secondary)

下划线指示器,视觉更轻量。

<Tabs value={activeTab} onValueChange={setActiveTab} variant="secondary">
  <Tabs.List>
    <Tabs.Indicator />
    <Tabs.Trigger value="overview">
      <Tabs.Label>概览</Tabs.Label>
    </Tabs.Trigger>
    <Tabs.Trigger value="analytics">
      <Tabs.Label>分析</Tabs.Label>
    </Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="overview">...</Tabs.Content>
  <Tabs.Content value="analytics">...</Tabs.Content>
</Tabs>

可滚动标签

标签较多时通过横向滚动容纳。

<Tabs value={activeTab} onValueChange={setActiveTab}>
  <Tabs.List>
    <Tabs.ScrollView scrollAlign="center">
      <Tabs.Indicator />
      <Tabs.Trigger value="tab1">
        <Tabs.Label>第一个</Tabs.Label>
      </Tabs.Trigger>
      <Tabs.Trigger value="tab2">
        <Tabs.Label>第二个</Tabs.Label>
      </Tabs.Trigger>
      <Tabs.Trigger value="tab3">
        <Tabs.Label>第三个</Tabs.Label>
      </Tabs.Trigger>
      <Tabs.Trigger value="tab4">
        <Tabs.Label>第四个</Tabs.Label>
      </Tabs.Trigger>
      <Tabs.Trigger value="tab5">
        <Tabs.Label>第五个</Tabs.Label>
      </Tabs.Trigger>
    </Tabs.ScrollView>
  </Tabs.List>
  <Tabs.Content value="tab1">...</Tabs.Content>
  <Tabs.Content value="tab2">...</Tabs.Content>
  <Tabs.Content value="tab3">...</Tabs.Content>
  <Tabs.Content value="tab4">...</Tabs.Content>
  <Tabs.Content value="tab5">...</Tabs.Content>
</Tabs>

禁用标签

使用 isDisabled 禁止与特定标签交互。

<Tabs value={activeTab} onValueChange={setActiveTab}>
  <Tabs.List>
    <Tabs.Indicator />
    <Tabs.Trigger value="active">
      <Tabs.Label>可用</Tabs.Label>
    </Tabs.Trigger>
    <Tabs.Trigger value="disabled" isDisabled>
      <Tabs.Label>已禁用</Tabs.Label>
    </Tabs.Trigger>
    <Tabs.Trigger value="another">
      <Tabs.Label>其他</Tabs.Label>
    </Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="active">...</Tabs.Content>
  <Tabs.Content value="another">...</Tabs.Content>
</Tabs>

与图标组合

图标与文字并用,信息更直观。

<Tabs value={activeTab} onValueChange={setActiveTab}>
  <Tabs.List>
    <Tabs.Indicator />
    <Tabs.Trigger value="home">
      <Icon name="home" size={16} />
      <Tabs.Label>首页</Tabs.Label>
    </Tabs.Trigger>
    <Tabs.Trigger value="search">
      <Icon name="search" size={16} />
      <Tabs.Label>搜索</Tabs.Label>
    </Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="home">...</Tabs.Content>
  <Tabs.Content value="search">...</Tabs.Content>
</Tabs>

使用渲染函数

Tabs.Trigger 上使用渲染函数,可读取选中状态并按需自定义内容。

<Tabs value={activeTab} onValueChange={setActiveTab}>
  <Tabs.List>
    <Tabs.Indicator />
    <Tabs.Trigger value="settings">
      {({ isSelected, value, isDisabled }) => (
        <Tabs.Label
          className={isSelected ? 'text-accent font-medium' : 'text-foreground'}
        >
          设置
        </Tabs.Label>
      )}
    </Tabs.Trigger>
    <Tabs.Trigger value="profile">
      {({ isSelected }) => (
        <>
          <Icon name="user" size={16} />
          <Tabs.Label className={isSelected ? 'text-accent' : 'text-muted'}>
            个人资料
          </Tabs.Label>
        </>
      )}
    </Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="settings">...</Tabs.Content>
  <Tabs.Content value="profile">...</Tabs.Content>
</Tabs>

与分隔线配合

在标签之间添加分隔线;可见性由 betweenValues 与当前激活项共同决定(详见下方 API)。

<Tabs value={activeTab} onValueChange={setActiveTab}>
  <Tabs.List>
    <Tabs.ScrollView>
      <Tabs.Indicator />
      <Tabs.Trigger value="general">
        <Tabs.Label>通用</Tabs.Label>
      </Tabs.Trigger>
      <Tabs.Separator betweenValues={['general', 'notifications']} />
      <Tabs.Trigger value="notifications">
        <Tabs.Label>通知</Tabs.Label>
      </Tabs.Trigger>
      <Tabs.Separator betweenValues={['notifications', 'profile']} />
      <Tabs.Trigger value="profile">
        <Tabs.Label>个人资料</Tabs.Label>
      </Tabs.Trigger>
    </Tabs.ScrollView>
  </Tabs.List>
  <Tabs.Content value="general">...</Tabs.Content>
  <Tabs.Content value="notifications">...</Tabs.Content>
  <Tabs.Content value="profile">...</Tabs.Content>
</Tabs>

示例

import {
  Button,
  Checkbox,
  Description,
  ControlField,
  Label,
  Tabs,
  TextField,
} from 'heroui-native';
import { useState } from 'react';
import { View, Text } from 'react-native';
import Animated, {
  FadeIn,
  FadeOut,
  LinearTransition,
} from 'react-native-reanimated';

const AnimatedContentContainer = ({
  children,
}: {
  children: React.ReactNode;
}) => (
  <Animated.View
    entering={FadeIn.duration(200)}
    exiting={FadeOut.duration(200)}
    className="gap-6"
  >
    {children}
  </Animated.View>
);

export default function TabsExample() {
  const [activeTab, setActiveTab] = useState('general');

  const [showSidebar, setShowSidebar] = useState(true);
  const [accountActivity, setAccountActivity] = useState(true);
  const [name, setName] = useState('');

  return (
    <Tabs value={activeTab} onValueChange={setActiveTab} variant="primary">
      <Tabs.List>
        <Tabs.ScrollView>
          <Tabs.Indicator />
          <Tabs.Trigger value="general">
            <Tabs.Label>通用</Tabs.Label>
          </Tabs.Trigger>
          <Tabs.Trigger value="notifications">
            <Tabs.Label>通知</Tabs.Label>
          </Tabs.Trigger>
          <Tabs.Trigger value="profile">
            <Tabs.Label>个人资料</Tabs.Label>
          </Tabs.Trigger>
        </Tabs.ScrollView>
      </Tabs.List>

      <Animated.View
        layout={LinearTransition.duration(200)}
        className="px-4 py-6 border border-border rounded-xl"
      >
        <Tabs.Content value="general">
          <AnimatedContentContainer>
            <ControlField
              isSelected={showSidebar}
              onSelectedChange={setShowSidebar}
            >
              <ControlField.Indicator variant="checkbox" />
              <View className="flex-1">
                <Label>显示侧边栏</Label>
                <Description>显示侧边导航面板</Description>
              </View>
            </ControlField>
          </AnimatedContentContainer>
        </Tabs.Content>

        <Tabs.Content value="notifications">
          <AnimatedContentContainer>
            <ControlField
              isSelected={accountActivity}
              onSelectedChange={setAccountActivity}
            >
              <ControlField.Indicator variant="checkbox" />
              <View className="flex-1">
                <Label>账户动态</Label>
                <Description>接收与账户活动相关的通知</Description>
              </View>
            </ControlField>
          </AnimatedContentContainer>
        </Tabs.Content>

        <Tabs.Content value="profile">
          <AnimatedContentContainer>
            <TextField isRequired>
              <Label>姓名</Label>
              <Input
                value={name}
                onChangeText={setName}
                placeholder="请输入全名"
              />
            </TextField>
            <Button size="sm" className="self-start">
              <Button.Label>更新资料</Button.Label>
            </Button>
          </AnimatedContentContainer>
        </Tabs.Content>
      </Animated.View>
    </Tabs>
  );
}

更多示例见 GitHub 仓库

API 参考

Tabs

proptype默认值描述
childrenReact.ReactNode-渲染在 Tabs 内的子元素
valuestring-当前激活的标签值
variant'primary' | 'secondary''primary'视觉变体
classNamestring-根容器额外 className
animation"disable-all" | undefinedundefined动画配置。设为 "disable-all" 可关闭全部动画(含子树)
onValueChange(value: string) => void-激活标签变化时的回调
...ViewPropsViewProps-支持 React Native View 的全部标准属性

Tabs.List

proptype默认值描述
childrenReact.ReactNode-渲染在列表内的子元素
classNamestring-额外 className
...ViewPropsViewProps-支持 React Native View 的全部标准属性

Tabs.ScrollView

proptype默认值描述
childrenReact.ReactNode-渲染在滚动视图内的子元素
scrollAlign'start' | 'center' | 'end' | 'none''center'选中项的滚动对齐方式
classNamestring-滚动容器额外 className
contentContainerClassNamestring-内容容器额外 className
...ScrollViewPropsScrollViewProps-支持 React Native ScrollView 的全部标准属性

Tabs.Trigger

proptype默认值描述
childrenReact.ReactNode | ((props: TabsTriggerRenderProps) => React.ReactNode)-子节点,或接收 TabsTriggerRenderProps 的渲染函数
valuestring-唯一标识该标签的值
isDisabledbooleanfalse是否禁用该触发器
classNamestring-额外 className
...PressablePropsPressableProps-支持 React Native Pressable 的全部标准属性

TabsTriggerRenderProps

使用渲染函数作为 children 时,会传入以下属性:

propertytype描述
isSelectedboolean当前触发器是否被选中
valuestring该触发器的值
isDisabledboolean该触发器是否禁用

Tabs.Label

proptype默认值描述
childrenReact.ReactNode-作为标签渲染的文本内容
classNamestring-额外 className
...TextPropsTextProps-支持 React Native Text 的全部标准属性

Tabs.Indicator

proptype默认值描述
childrenReact.ReactNode-自定义指示器内容
classNamestring-额外 className
animationTabsIndicatorAnimation-动画配置
isAnimatedStyleActivebooleantrue是否启用 Reanimated 动画样式
...Animated.ViewPropsAnimated.ViewProps-支持 Reanimated Animated.View 的全部属性

TabsIndicatorAnimation

Tabs.Indicator 的动画配置,可为:

  • false"disabled":关闭所有动画
  • trueundefined:使用默认动画
  • object:自定义动画配置
proptype默认值描述
state'disabled' | boolean-自定义属性时用于禁用动画
width.type'spring' | 'timing''spring'宽度动画类型
width.configWithSpringConfig | WithTimingConfig{ stiffness: 1200, damping: 120 }(spring)或 { duration: 200 }(timing)Reanimated 动画配置
height.type'spring' | 'timing''spring'高度动画类型
height.configWithSpringConfig | WithTimingConfig同上Reanimated 动画配置
translateX.type'spring' | 'timing''spring'水平位移动画类型
translateX.configWithSpringConfig | WithTimingConfig同上Reanimated 动画配置

Tabs.Separator

proptype默认值描述
betweenValuesstring[]-分隔线两侧对应的标签值数组。当当前标签值不在该数组中时,分隔线可见(与可见性动画联动)
isAlwaysVisiblebooleanfalsetrue 时透明度恒为 1,不受当前标签影响
classNamestring-额外 className
animationTabsSeparatorAnimation-动画配置
isAnimatedStyleActivebooleantrue是否启用 Reanimated 动画样式
childrenReact.ReactNode-自定义分隔线内容
...Animated.ViewPropsAnimated.ViewProps-支持 Reanimated Animated.View 的全部属性

说明: 以下样式属性由动画占用,不能仅通过 className 覆盖:

  • opacity:用于分隔线显隐过渡(当前标签在 betweenValues 内时为 0,否则为 1)

若要调整这些属性,请使用 animation。若需完全关闭动画样式、改用自己的 classNamestyle,请设置 isAnimatedStyleActive={false}

TabsSeparatorAnimation

Tabs.Separator 的动画配置,可为:

  • false"disabled":关闭所有动画
  • trueundefined:使用默认动画
  • object:自定义动画配置
proptype默认值描述
state'disabled' | boolean-自定义属性时用于禁用动画
opacity.value[number, number][0, 1]透明度区间 [隐藏, 显示]
opacity.timingConfigWithTimingConfig{ duration: 200 }时长类动画配置

Tabs.Content

proptype默认值描述
childrenReact.ReactNode-渲染在面板内的子元素
valuestring-该内容与哪个标签值对应
classNamestring-额外 className
...ViewPropsViewProps-支持 React Native View 的全部标准属性

Hooks

useTabs

在自定义组件或复合子组件中读取 Tabs 根上下文。

import { useTabs } from 'heroui-native';

const CustomComponent = () => {
  const { value, onValueChange, nativeID } = useTabs();
  // ...你的实现
};

返回值

类型:UseTabsReturn

propertytype描述
valuestring当前激活的标签值
onValueChange(value: string) => void用于切换激活标签的回调
nativeIDstring该 Tabs 实例的唯一标识

说明: 必须在 Tabs 内使用;在上下文外调用会抛错。

useTabsMeasurements

读取标签测量上下文,用于管理各触发器的位置与尺寸。

import { useTabsMeasurements } from 'heroui-native';

const CustomIndicator = () => {
  const { measurements, variant } = useTabsMeasurements();
  // ...你的实现
};

返回值

类型:UseTabsMeasurementsReturn

propertytype描述
measurementsRecord<string, ItemMeasurements>各标签触发器的测量数据
setMeasurements(key: string, measurements: ItemMeasurements) => void更新指定触发器的测量数据
variant'primary' | 'secondary'当前 Tabs 的视觉变体

ItemMeasurements

propertytype描述
widthnumber触发器宽度(像素)
heightnumber触发器高度(像素)
xnumber触发器的 x 坐标

说明: 必须在 Tabs 内使用;在上下文外调用会抛错。

useTabsTrigger

在自定义组件或复合子组件中读取单个 Tabs.Trigger 的上下文。

import { useTabsTrigger } from 'heroui-native';

const CustomLabel = () => {
  const { value, isSelected, nativeID } = useTabsTrigger();
  // ...你的实现
};

返回值

类型:UseTabsTriggerReturn

propertytype描述
valuestring该触发器的值
nativeIDstring该触发器的唯一标识
isSelectedboolean当前触发器是否被选中

说明: 必须在 Tabs.Trigger 内使用;在上下文外调用会抛错。

本页目录