鸿蒙应用开发中,如何深入解析并演示Tabs标签导航组件?

摘要:【学习目标】 掌握 Tabs 组件核心定位、基础结构与使用规范,理解 TabContent 的布局限制 通过示例实现底部顶部侧边三种标准导航布局 掌握 barMode、scrollable、animationDuration 等常用属性
【学习目标】 掌握 Tabs 组件核心定位、基础结构与使用规范,理解 TabContent 的布局限制 通过示例实现底部/顶部/侧边三种标准导航布局 掌握 barMode、scrollable、animationDuration 等常用属性配置 学会自定义 TabBar、代码控制切换、切换拦截等进阶用法 一、本节工程目录结构(API20) TabsDemo/ └── entry/ └── src/ └── main/ ├── ets/ │ ├── components/ # 自定义公共组件 │ │ ├── CustomTabBar.ets │ │ └── HomeComponent.ets │ ├── pages/ # 主页面 + 示例页 │ │ ├── Index.ets 课程导航主页 │ │ ├── BasicTabs.ets 基础三方向导航示例 │ │ ├── BuilderTabs.ets @Builder 自定义TabBar │ │ └── CustomTabs.ets 完全自定义异形TabBar │ └── entryability/ │ └── EntryAbility.ets └── resources/ └── base/ └── media/ 二、Tabs 核心基础认知 2.1 什么是 Tabs 组件 Tabs 是鸿蒙中实现单页面多视图快速切换的导航组件,广泛用于应用主界面底部导航、内容分类顶部导航等场景,是 App 开发中最常用的导航容器之一。 2.2 组件结构 Tabs 由三部分组成,必须一一对应: Tabs 容器:管理整体布局、动画、滑动、事件 TabBar:每个页面的导航标签 TabContent:每个标签对应的内容区域 2.3 使用规则 TabContent 不建议手动设置宽高,默认撑满 Tabs 剩余空间 TabContent 书写顺序就是页签索引顺序,从 0 开始 每个 TabContent 必须配置 .tabBar(),否则页签不显示 TabsController 可以手动控制选中哪个 onContentWillChange 可以提前拦截点击。 三、基础示例(pages/BasicTabs.ets) @Entry @Component struct BasicTabs { @State currentIndex: number = 0; @State barPos: BarPosition = BarPosition.End; @State isVertical: boolean = false; // 1. 创建 Tabs 控制器(代码跳转用) private tabsController: TabsController = new TabsController(); build() { Column() { Row({ space: 12 }) { Button("底部导航").onClick(() => { this.barPos = BarPosition.End; this.isVertical = false; }) Button("顶部导航").onClick(() => { this.barPos = BarPosition.Start; this.isVertical = false; }) Button("侧边导航").onClick(() => { this.barPos = BarPosition.Start; this.isVertical = true; }) } .margin(12) .justifyContent(FlexAlign.Center) // 2. 绑定 controller Tabs({ barPosition: this.barPos, index: this.currentIndex, controller: this.tabsController }) { TabContent() { Column() { Text("首页内容").fontSize(30) // 3. 按钮代码控制跳转 Button("跳转到发现").onClick(() => { this.tabsController.changeIndex(2); }).margin({top:10}); } .width('100%') .height('100%') .backgroundColor('#F5F5F5') .justifyContent(FlexAlign.Center) } .tabBar("首页") TabContent() { Column() { Text("分类内容").fontSize(30) } .width('100%') .height('100%') .backgroundColor('#F5F5F5') .justifyContent(FlexAlign.Center) } .tabBar("分类") TabContent() { Column() { Text("发现内容").fontSize(30) } .width('100%') .height('100%') .backgroundColor('#F5F5F5') .justifyContent(FlexAlign.Center) } .tabBar("发现") TabContent() { Column() { Text("我的内容").fontSize(30) } .width('100%') .height('100%') .backgroundColor('#F5F5F5') .justifyContent(FlexAlign.Center) } .tabBar("我的") } .layoutWeight(1) .vertical(this.isVertical) .barWidth(this.isVertical ? 120 : '100%') .barHeight(this.isVertical ? '100%' : 50) .onChange(index => this.currentIndex = index) // 4. 切换拦截(演示:禁止跳转到“我的”页面) .onContentWillChange((from: number, to: number) => { if (to === 3) { console.log("拦截成功:无法进入我的页面!"); return false; // 返回 false 阻止跳转 } return true; }) } .width('100%') .height('100%') } } 运行效果 三种布局对应配置 布局 barPosition vertical 典型场景 底部导航 BarPosition.End false 应用主入口 顶部导航 BarPosition.Start false 内容分类、资讯标签 侧边导航 BarPosition.Start true 平板、横屏、管理后台 四、Tabs 常用属性配置 4.1 barMode:导航栏模式 BarMode.Fixed:均分宽度,不可滚动(默认) BarMode.Scrollable:可横向滚动,适合多标签 4.2 scrollable:是否允许滑动切换 嵌套导航时建议关闭,避免滑动冲突。 4.3 animationDuration:切换动画时长 单位:毫秒,默认 300。 4.4 cachedMaxCount:页面缓存数量(API19+) 提升切换流畅度。 4.5 AnimationMode 切换动画模式 enum AnimationMode { CONTENT_FIRST = 0, // 先加载页面内容,再执行切换动画 ACTION_FIRST = 1, // 先执行切换动画,再加载页面内容 NO_ANIMATION = 2, // 无任何动画,直接切换页面(本案例常用) CONTENT_FIRST_WITH_JUMP = 3, // 先加载页面,无动画跳转,再执行动画 ACTION_FIRST_WITH_JUMP = 4 // 先无动画跳转,再执行动画 } 五、@Builder 自定义 TabBar(pages/BuilderTabs.ets) @Entry @Component struct BuilderTabs { @State currentIndex: number = 0; @Builder TabItem(title: string, index: number, nor: Resource, sel: Resource,) { Column({ space: 4 }) { Image(this.currentIndex === index ? sel : nor).size({ width: 24, height: 24 }) Text(title).fontSize(12).fontColor(this.currentIndex === index ? '#07C160' : '#999') } .width('100%') .justifyContent(FlexAlign.Center) } build() { Column() { Tabs({ barPosition: BarPosition.End, index: this.currentIndex }) { TabContent() { Column() { Text("首页").fontSize(30) }.width('100%').height('100%').justifyContent(FlexAlign.Center) } .tabBar(this.TabItem("首页", 0, $r('app.media.tab_wechat_normal'), $r('app.media.tab_wechat_selected'))) TabContent() { Column() { Text("分类").fontSize(30) }.width('100%').height('100%').justifyContent(FlexAlign.Center) } .tabBar(this.TabItem("分类", 1, $r('app.media.tab_contact_normal'), $r('app.media.tab_contact_selected'))) TabContent() { Column() { Text("发现").fontSize(30) }.width('100%').height('100%').justifyContent(FlexAlign.Center) } .tabBar(this.TabItem("发现", 2, $r('app.media.tab_find_normal'), $r('app.media.tab_find_selected'))) TabContent() { Column() { Text("我的").fontSize(30) }.width('100%').height('100%').justifyContent(FlexAlign.Center) } .tabBar(this.TabItem("我的", 3, $r('app.media.tab_mine_normal'), $r('app.media.tab_mine_selected'))) } .scrollable(false) .animationMode(AnimationMode.NO_ANIMATION) .onChange(index => this.currentIndex = index) } .width('100%') .height('100%') } } 运行效果 六、完全自定义TabBar 6.1 自定义导航组件(components/CustomTabBar.ets) import { CustomTabBar } from '../components/CustomTabBar' import { HomeComponent } from '../components/HomeComponent'; @Entry @Component struct CustomTabs { @State currentIndex: number = 0; build() { Column() { Tabs({ index: this.currentIndex }) { TabContent() { HomeComponent() } TabContent() { Text("发现").fontSize(30).width('100%').height('100%').textAlign(TextAlign.Center) } TabContent() { Text("发布").fontSize(30).width('100%').height('100%').textAlign(TextAlign.Center) } TabContent() { Text("消息").fontSize(30).width('100%').height('100%').textAlign(TextAlign.Center) } TabContent() { Text("我的").fontSize(30).width('100%').height('100%').textAlign(TextAlign.Center) } } .scrollable(false) .barHeight(0) .layoutWeight(1) .barMode(BarMode.Fixed) .animationMode(AnimationMode.NO_ANIMATION) CustomTabBar({ currentIndex: $currentIndex, tabList: [ { title: "首页" }, { title: "发现" }, { normalImg: $r('app.media.ic_add'), selectedImg: $r('app.media.ic_add') }, { title: "消息" }, { title: "我的" } ], onTabClick: (idx) => { this.currentIndex = idx } }) } .width('100%') .height('100%') } } 6.2 首页顶部导航组件(components/HomeComponent.ets) @Component export struct HomeComponent { build() { Tabs({ barPosition: BarPosition.Start }) { TabContent() { Column() { Text("关注页面").fontSize(30) }.backgroundColor(Color.Pink) .width('100%') .height('100%') .justifyContent(FlexAlign.Center) } .tabBar({text:"关注"}) TabContent() { Column() { Text("发现页面").fontSize(30) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) } .tabBar("发现") TabContent() { Column() { Text("北京页面").fontSize(30) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) } .tabBar("北京") } .barMode(BarMode.Fixed) .barHeight(44) .backgroundColor($r('sys.color.ohos_id_list_background_color')) .cachedMaxCount(3,TabsCacheMode.CACHE_LATEST_SWITCHED) .width('100%') } } 6.3 父页面(pages/CustomTabs.ets) import { CustomTabBar } from '../components/CustomTabBar' import { HomeComponent } from '../components/HomeComponent'; @Entry @Component struct CustomTabs { @State currentIndex: number = 0; build() { Column() { Tabs({ index: this.currentIndex }) { TabContent() { HomeComponent() } TabContent() { Text("发现").fontSize(30).width('100%').height('100%').textAlign(TextAlign.Center) } TabContent() { Text("发布").fontSize(30).width('100%').height('100%').textAlign(TextAlign.Center) } TabContent() { Text("消息").fontSize(30).width('100%').height('100%').textAlign(TextAlign.Center) } TabContent() { Text("我的").fontSize(30).width('100%').height('100%').textAlign(TextAlign.Center) } } .scrollable(false) .barHeight(0) // 自定义tabar后 需要吧系统的设置为0,否则会占位 .layoutWeight(1) .barMode(BarMode.Fixed) .animationMode(AnimationMode.NO_ANIMATION) CustomTabBar({ currentIndex: $currentIndex, tabList: [ { title: "首页" }, { title: "发现" }, { normalImg: $r('app.media.ic_add'), selectedImg: $r('app.media.ic_add') }, { title: "消息" }, { title: "我的" } ], onTabClick: (idx) => { this.currentIndex = idx } }) } .width('100%') .height('100%') } } 运行效果 七、知识点总结 Tabs = 容器 + TabBar + TabContent 支持底部/顶部/侧边三种导航模式 可配置滚动、动画、缓存、指示器等 @Builder 可快速实现统一样式 TabBar TabsController 实现代码控制跳转 onContentWillChange 实现页面切换拦截 完全自定义组件可实现异形突出效果 八、代码仓库 工程名称:TabsDemo 仓库地址:https://gitee.com/HarmonyOS-UI-Basics/harmony-os-ui-basics.git 九、下节预告 下一节我们将学习媒体查询 @ohos.mediaquery 响应式布局,实现横竖屏、深浅色模式与多设备自适应,并封装通用媒体查询工具类。