在这里插入图片描述

一、应用概述

标签页(Top Tabs Demo)是一个顶部标签切换应用,四个标签(推荐、关注、热门、附近)对应不同的内容页面,点击标签切换并带有下划线指示器。这是典型的顶部导航模式,广泛用于新闻客户端、社交应用的内容分类场景。

与第 46 个应用(底部导航)不同,顶部标签页更强调内容分类展示而非全局导航。在 HarmonyOS 中,这个应用展示了 Row 标签栏 + 下划线指示器 的自定义实现方式,以及 Text 组件的详细样式控制。

二、技术架构

2.1 应用结构

┌─────────────────────────────────────┐
│  ‹ 返回           📑 标签页          │
├─────────────────────────────────────┤
│  ┌──────┬──────┬──────┬──────┐     │
│  │ 推荐  │ 关注  │ 热门  │ 附近  │     │  ← 标签栏
│  │ ▔▔▔  │       │       │       │     │  ← 下划线指示器
│  └──────┴──────┴──────┴──────┘     │
├─────────────────────────────────────┤
│                                     │
│   🔥 热门推荐                      │
│                                     │
│   这里有最新的内容推荐              │
│   每天更新优质内容                  │
│   不要错过精彩推荐                  │
│                                     │
│                                     │
├─────────────────────────────────────┤
│  点击标签切换内容                    │
└─────────────────────────────────────┘

2.2 数据模型

interface TabContent {
  title: string;   // 标签名称
  content: string; // 页面内容(含 emoji 和换行)
}

2.3 状态变量

变量 类型 用途
currentTab number 当前选中的标签索引
tabs TabContent[] 4 个标签配置

三、核心代码深度解析

3.1 标签栏与下划线指示器

顶部标签栏的核心设计是标签文字 + 底部下划线的组合:

Row() {
  ForEach(this.tabs, (tab: TabContent, idx: number) => {
    Column() {
      Text(tab.title).fontSize(16)
        .fontColor(this.currentTab === idx ? '#0077FF' : '#999')
        .fontWeight(this.currentTab === idx ? FontWeight.Bold : FontWeight.Regular)
      
      // 下划线指示器
      if (this.currentTab === idx) {
        Text('').width('80%').height(3).backgroundColor('#0077FF').borderRadius(2).margin({ top: 4 })
      }
    }
    .layoutWeight(1).alignItems(HorizontalAlign.Center)
    .padding({ top: 8, bottom: 8 })
    .onClick(() => { this.currentTab = idx })
  })
}
.width('92%').backgroundColor('#f0f0f0').borderRadius(12).margin({ bottom: 16 })

下划线指示器的实现细节

Text('').width('80%').height(3).backgroundColor('#0077FF').borderRadius(2).margin({ top: 4 })

这是一个「空 Text 组件做装饰」的技巧:

  • Text(''):空字符串,无文字内容
  • width('80%'):宽度为父容器(Column)的 80%,非全宽
  • height(3):3vp 高的横条
  • backgroundColor('#0077FF'):主题蓝色
  • borderRadius(2):两端圆角,平滑过渡

80% 宽度的目的是让下划线比标签文字略窄,视觉上更精致。如果设为 100%,下划线会从标签左边缘延伸到右边缘,显得过于生硬。

选中状态样式对比

属性 未选中 选中
文字颜色 #999 灰色 #0077FF 主题蓝
字重 Regular Bold
下划线 蓝色横条

3.2 内容区域

Column() {
  Text(this.tabs[this.currentTab].content)
    .fontSize(16).fontColor('#555').lineHeight(30).textAlign(TextAlign.Center)
}
.layoutWeight(1).justifyContent(FlexAlign.Center)
.width('92%').backgroundColor('#fff').borderRadius(16).padding(24)
.alignItems(HorizontalAlign.Center)

内容区域的设计:

  • 白色卡片backgroundColor('#fff') + borderRadius(16),形成卡片风格
  • 内边距 24:保证文字与卡片边缘有充足留白
  • lineHeight(30):行高 30vp,对 16pt 字体来说大约是 1.875 倍,阅读舒适
  • 居中布局justifyContent(Center) + alignItems(Center) 让内容在卡片内居中

3.3 标签栏背景

.backgroundColor('#f0f0f0').borderRadius(12)

标签栏使用浅灰色 #f0f0f0 背景和 12vp 圆角,形成一个独立的「容器」:

  • 灰色背景将四个标签视觉上「包裹」在一起
  • 圆角 12vp 让这个容器不再棱角分明
  • 与下方的白色内容卡片形成背景灰 + 内容白的对比层次

四、HarmonyOS 特色功能深度解析

4.1 Row 容器内的 Column 嵌套

每个标签的结构是 Row > Column > (Text + Text)

Row() {           ← 水平排列标签
  Column() {      ← 垂直排列文字 + 下划线
    Text()        ← 标签文字
    Text('')      ← 下划线指示器
  }
}

这种嵌套结构的原因:Row 是水平方向的,但每个标签需要将「文字」和「下划线」垂直堆叠,所以每个标签内部需要一个 Column。这是 ArkUI 中行列嵌套的典型模式。

4.2 alignItems(HorizontalAlign.Center)

.alignItems(HorizontalAlign.Center)

Column 中设置子组件的水平对齐方式:

  • HorizontalAlign.Center:子组件在 Column 中水平居中
  • 这使得下划线(80% 宽度)在标签的 Column 中居中显示

4.3 条件渲染下划线

if (this.currentTab === idx) {
  Text('').width('80%').height(3).backgroundColor('#0077FF').borderRadius(2).margin({ top: 4 })
}

只有选中的标签才渲染下划线组件。当 currentTab 变化时:

  1. 旧选中标签的下划线被销毁
  2. 新选中标签的下划线被创建

ArkUI 框架会自动处理组件的创建和销毁,开发者只需关注状态逻辑。

五、UI/UX 设计分析

5.1 四标签内容设计

四个标签的内容各有特色:

标签 内容主题 文案风格
推荐 🔥 热门推荐 动态、更新、勿错过
关注 👥 关注动态 互动、实时、发现
热门 📈 热门排行 排行、趋势、大家都在看
附近 📍 附近的人 发现、探索、认识

每个标签的内容都包含一个 emoji 前缀(🔥👥📈📍),增强视觉识别度。

5.2 卡片式内容设计

内容区域采用白色卡片设计:

  • 圆角 16vp:比标签栏的 12vp 更大,视觉层次更柔和
  • 内边距 24vp:充足呼吸空间
  • 居中文字:适合短文本展示

5.3 交互反馈

  1. 点击标签:文字颜色 + 字重 + 下划线同时变化
  2. 下划线动画:当前实现中下划线是突然出现和消失的,没有滑动动画

添加下划线滑动动画的改进方案

// 使用 animateTo 实现下划线平滑移动
animateTo({ duration: 250 }, () => {
  this.currentTab = idx;
});

// 或者使用 offset 偏移量控制下划线位置
Text('')
  .width('20%')  // 每个标签占 25%,下划线宽度略窄
  .height(3)
  .backgroundColor('#0077FF')
  .borderRadius(2)
  .offset({ x: this.currentTab * 100 + 10 })  // 根据索引计算偏移
  .animation({ duration: 250 })

六、最佳实践与优化建议

6.1 当前代码亮点

  1. 简洁的数据驱动currentTab 一个变量控制标签选中状态和内容显示
  2. 纯 ArkTS 实现:不依赖第三方库,完全使用 ArkUI 原生组件
  3. 响应式布局layoutWeight(1) 实现标签等分
  4. 优雅的视觉层次:灰底标签栏 + 白底内容卡片的对比

6.2 可优化方向

// 优化建议 1:可滑动标签栏
// 当标签数量多时,使用 Scroll 包裹标签栏实现横向滚动
Scroll() {
  Row() {
    ForEach(this.tabs, (tab, idx) => {
      // 标签内容
    })
  }
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)

// 优化建议 2:使用 Tabs 原生组件
// HarmonyOS 的 Tabs 组件提供了更完整的标签页功能
Tabs({ index: this.currentTab }) {
  ForEach(this.tabs, (tab: TabContent, idx: number) => {
    TabContent() {
      // 内容区域
    }
    .tabBar(tab.title)
  })
}
.barWidth('92%')
// 支持滑动切换、动画指示器等

// 优化建议 3:内容懒加载
// 仅在标签被选中时加载内容
if (this.currentTab === idx) {
  // 加载该标签的内容
}

// 优化建议 4:添加 badge 角标
Column() {
  Stack() {
    Text(tab.title)
    if (tab.badge) {
      Text(tab.badge).fontSize(10).fontColor('#fff')
        .backgroundColor('#F44336').borderRadius(10)
        .padding({ left: 4, right: 4 }).height(16)
        .align(Alignment.TopEnd)
    }
  }
}

// 优化建议 5:下拉刷新
// 配合 Refresh 组件实现内容刷新
Refresh({ refreshing: $isRefreshing, onRefresh: () => this.loadContent() }) {
  // 内容区域
}

6.3 性能优化

  • Tabs 原生组件 vs 自定义实现:对于简单场景,自定义实现更灵活;对于需要滑动切换、动画指示器等高级功能,建议使用 Tabs 原生组件
  • 内容组件化:将每个标签的内容抽取为独立的 @Component,利用 ArkUI 的组件复用机制提升性能
  • 避免过度渲染:如果标签内容较重(如图片、列表),应只在标签选中时渲染内容

七、总结与扩展

顶部标签页应用展示了 ArkUI 中实现内容分类切换的标准模式:

知识点 应用位置 重要程度
条件渲染 if 下划线指示器 ★★★★★
Row + Column 嵌套 标签栏结构 ★★★★★
layoutWeight 弹性布局 标签等分 ★★★★☆
Text 样式控制 颜色/字重/下划线 ★★★★☆
alignItems 对齐 内容居中 ★★★☆☆
borderRadius 圆角 标签栏/卡片 ★★★☆☆

扩展思路

  1. 动画下划线:使用 animateTotransition 实现下划线平滑滑动效果
  2. 滑动切换:添加 SwipeGesture 或使用 Tabs 原生组件支持手势滑动切换
  3. 标签关闭:部分标签支持关闭(如浏览器标签页),添加 ✕ 关闭按钮
  4. 标签排序:长按拖拽排序,使用 PanGestureonDrag 实现
  5. 多行标签:标签数量过多时自动换行或折叠显示
  6. 深色模式:根据系统主题切换标签栏和内容区域的配色

顶部标签页和底部导航(上篇)构成了移动应用导航的「上下双雄」——顶部标签用于内容分类,底部导航用于全局页面切换。掌握这两种模式,你就能应对绝大多数 App 的导航设计需求。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐