当前位置: 首页 > news >正文

HarmonyOS 实战教程(三):Navigation 导航体系与自定义 TabBar —— 以「柚兔自测量表」为例

一、HarmonyOS 导航体系概览

HarmonyOS NEXT 推荐使用Navigation+NavPathStack替代传统的router进行页面导航。Navigation 提供了统一的导航容器,支持栈管理、转场动画和路由拦截,是构建复杂应用的标配方案。

二、主页面导航架构

MeCharts 的主页面Index.ets采用了Navigation + Tabs的组合架构:

@Entry@ComponentV2struct Index{privatetabController:TabsController=newTabsController();@LocalcurrentIndex:number=0;privatepageContext:PageContext=AppStorage.get('pageContext')asPageContext;privateappPathInfo:NavPathStack=this.pageContext.navPathStack;aboutToAppear():void{BackupManagerService.getInstance().initializeBackupManager();letcallback:Callback<emitter.EventData>=(eventData:emitter.EventData)=>{this.tabController.changeIndex(2);};emitter.on(CommonConstants.EVENT_ID,callback);}aboutToDisappear():void{emitter.off(CommonConstants.EVENT_ID);}build(){Navigation(this.appPathInfo){Column(){this.TabComponent()CustomTabBar({currentIndex:this.currentIndex,tabBarChange:(currentIndex:number)=>{this.currentIndex=currentIndex;}})}.height('100%').width('100%')}.hideTitleBar(true).mode(NavigationMode.Stack).height('100%').width('100%')}@BuilderTabComponent(){Tabs({controller:this.tabController,index:this.currentIndex}){TabContent(){HomeView()}.height('100%')TabContent(){ConsultView()}.height('100%')TabContent(){MineView()}.height('100%')}.onAnimationStart((index:number,targetIndex:number)=>{this.currentIndex=targetIndex;}).animationMode(AnimationMode.NO_ANIMATION).barWidth(0).barHeight(0).scrollable(false).layoutWeight(1).width('100%')}}

2.1 关键设计点

1)Navigation 与 NavPathStack 绑定

privateappPathInfo:NavPathStack=this.pageContext.navPathStack;Navigation(this.appPathInfo){// 内容区}

Navigation 组件接收NavPathStack作为参数,所有的页面跳转都通过操作这个栈来实现。

2)隐藏原生 TabBar

.barWidth(0).barHeight(0).scrollable(false)

将 Tabs 的原生导航栏宽高设为 0,禁用手势滑动,完全由自定义 TabBar 控制切换。

3)事件驱动的跨组件通信

aboutToAppear():void{letcallback:Callback<emitter.EventData>=(eventData:emitter.EventData)=>{this.tabController.changeIndex(2);// 切换到"我的"Tab};emitter.on(CommonConstants.EVENT_ID,callback);}

使用emitter(HarmonyOS 的事件总线)监听来自其他页面的事件。例如,AI 咨询页检测到用户未登录时,发送事件切换到"我的"Tab 触发登录。

三、自定义 TabBar 组件

MeCharts 没有使用 Tabs 自带的导航栏,而是实现了一个功能更丰富的自定义 TabBar:

@Componentexportstruct CustomTabBar{@StorageProp('GlobalInfoModel')globalInfoModel:GlobalInfoModel=AppStorage.get('GlobalInfoModel')!;@StorageProp('BlurRenderGroup')blurRenderGroup:boolean=false;@Prop@RequirecurrentIndex:number;tabBarChange:(index:number)=>void=(index:number)=>{};@BuilderTabItemBuilder(tabBar:TabBarData){Column(){SymbolGlyph(tabBar.icon).fontSize($r('sys.float.Title_M')).fontColor(tabBar.id===this.currentIndex?[$r('sys.color.interactive_active')]:[$r('sys.color.font_tertiary')]).renderingStrategy(SymbolRenderingStrategy.MULTIPLE_OPACITY).symbolEffect(newBounceSymbolEffect(EffectScope.LAYER,EffectDirection.UP),tabBar.id===this.currentIndex)Text(tabBar.title).fontSize($r('sys.float.Caption_M')).margin({top:$r('sys.float.padding_level1')}).fontWeight(FontWeight.Medium).fontColor(tabBar.id===this.currentIndex?$r('sys.color.interactive_active'):$r('sys.color.font_tertiary'))}.width('100%').height(50).onClick(()=>{if(this.currentIndex!==tabBar.id){this.tabBarChange(tabBar.id);}}).alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)}build(){Flex({direction:newBreakpointType({sm:FlexDirection.ColumnReverse,md:FlexDirection.ColumnReverse,lg:FlexDirection.Row,}).getValue(this.globalInfoModel.currentBreakpoint),alignItems:ItemAlign.Center,}){Flex({direction:newBreakpointType({sm:FlexDirection.Row,md:FlexDirection.Row,lg:FlexDirection.Column,}).getValue(this.globalInfoModel.currentBreakpoint),alignItems:ItemAlign.Center,justifyContent:FlexAlign.SpaceAround,}){ForEach(TABS_LIST,(item:TabBarData)=>{this.TabItemBuilder(item)},(item:TabBarData)=>JSON.stringify(item)+this.currentIndex)}.margin({bottom:newBreakpointType({sm:this.globalInfoModel.naviIndicatorHeight,md:this.globalInfoModel.naviIndicatorHeight,lg:0,}).getValue(this.globalInfoModel.currentBreakpoint),})}.backgroundBlurStyle(BlurStyle.COMPONENT_THICK).renderGroup(this.blurRenderGroup)}}

3.1 核心技术点

1)SymbolGlyph 系统图标 + 动效

SymbolGlyph(tabBar.icon).renderingStrategy(SymbolRenderingStrategy.MULTIPLE_OPACITY).symbolEffect(newBounceSymbolEffect(EffectScope.LAYER,EffectDirection.UP),tabBar.id===this.currentIndex)

HarmonyOS 提供了丰富的系统 Symbol 图标,支持多色渲染策略和弹性动效(BounceSymbolEffect),在 Tab 切换时呈现精致的动画反馈。

2)响应式布局

direction:newBreakpointType({sm:FlexDirection.ColumnReverse,// 小屏:底部水平排列md:FlexDirection.ColumnReverse,// 中屏:底部水平排列lg:FlexDirection.Row,// 大屏:左侧垂直排列}).getValue(this.globalInfoModel.currentBreakpoint)

使用自定义的BreakpointType工具类,根据当前断点动态决定布局方向。小屏设备(手机)TabBar 在底部水平排列;大屏设备(平板)TabBar 在左侧垂直排列。

3)毛玻璃效果

.backgroundBlurStyle(BlurStyle.COMPONENT_THICK)

TabBar 使用COMPONENT_THICK模糊样式,在滚动内容透过时呈现毛玻璃效果,提升视觉层次感。

4)底部安全区域避让

.margin({bottom:newBreakpointType({sm:this.globalInfoModel.naviIndicatorHeight,// 手机:留出导航条空间md:this.globalInfoModel.naviIndicatorHeight,lg:0,// 平板:无需避让}).getValue(this.globalInfoModel.currentBreakpoint),})

四、TabBar 数据模型

TabBar 的数据来源于TabBarModel.ets

exportinterfaceTabBarData{id:TabBarType;title:ResourceStr;icon:Resource;}exportconstTABS_LIST:TabBarData[]=[{id:TabBarType.HOME,icon:$r('sys.symbol.archivebox_fill'),title:$r('app.string.tab_home'),},{id:TabBarType.CONSULT,icon:$r('sys.symbol.discover_fill'),title:$r("app.string.tab_consult"),},{id:TabBarType.MINE,icon:$r('sys.symbol.person_crop_circle_fill_1'),title:$r('app.string.tab_mine'),},]

使用sys.symbol.*引用系统图标,使用app.string.*引用应用字符串资源,便于国际化。

五、PageContext 导航封装

MeCharts 将NavPathStack操作封装为PageContext,提供统一的导航接口:

exportinterfaceRouterParam{routerName:string;param?:object;onReturn?:(data?:object)=>void;}exportclassPageContextimplementsIPageContext{privatereadonlypathStack:NavPathStack;privatereturnCallback?:(data?:object)=>void;publicopenPage(data:RouterParam,animated:boolean=true):void{this.returnCallback=data.onReturn;this.pathStack.pushPath({name:data.routerName,param:data.param,},animated);}publicpopPage(animated:boolean=true,returnData?:object):void{if(this.returnCallback){this.returnCallback(returnData);this.returnCallback=undefined;}this.pathStack.pop(animated);}publicreplacePage(data:RouterParam,animated:boolean=true):void{this.pathStack.replacePath({name:data.routerName,param:data.param,},animated);}}

5.1 页面跳转示例

从首页跳转到 ABC 量表页面:

this.pageContext.openPage({param:{title:'ABC量表',}asResultParams,routerName:'AbcListPage',},true);

从答题页面替换为结果页面(不可返回):

this.pageContext.replacePage({routerName:'ResultPage',param:{score:totalScore,type:FormType.TYPE_ABC,title:this.title}asResultParams,},true);

5.2 NavDestination 接收参数

子页面通过NavDestinationonReady回调接收参数:

NavDestination(){// 页面内容}.onReady((ctx:NavDestinationContext)=>{constparams=ctx.pathInfo.paramasResultParams;this.title=params.titleasstring;this.type=params.typeasnumber;})

5.3 路由注册

每个子页面需要在路由配置文件中注册,并导出 Builder 函数:

@BuilderexportfunctionAbcListPageBuilder(){AbcListPage()}

这个 Builder 函数在router_map.json中被引用,Navigation 在路由跳转时通过它创建页面实例。

六、小结

本篇讲解了 Navigation + NavPathStack 的导航体系实现,以及自定义 TabBar 的响应式布局与系统动效。MeCharts 通过PageContext封装导航操作,使页面跳转逻辑简洁统一。下一篇将深入首页(HomeView)的布局实现,讲解 Swiper 轮播与 Grid 网格布局。

http://www.jsqmd.com/news/1263946/

相关文章:

  • 中医AR小程序开发:AI穴位识别与智能推荐实践
  • TCP协议细节与Web性能:web-performance教你如何突破传输层瓶颈
  • 从零自制500W轴向磁通电机:电磁设计、绕线工艺与FOC驱动全解析
  • ScaleDown批量处理教程:一次压缩100个提示词的高效方法
  • 如何在5分钟内上手PSone.css?新手必备快速启动教程
  • Buzz监控告警:及时发现并解决平台异常问题
  • 5分钟搞定Windows 11系统优化:Win11Debloat一键清理与性能提升指南
  • 标题:做环保空调专业的厂家盘点|2026工业厂房降温选型深度解析​ - 厂房车间降温方案
  • Generative Manim核心功能解析:LLM驱动的Manim代码生成与视频渲染技术
  • 自编码器实现语义与像素空间双向映射的创新方法
  • SpERT数据集处理教程:CoNLL04、SciERC与ADE数据获取与转换
  • 虚拟DOM与React性能优化:web-performance项目核心技术解析
  • AI Agent工程:2026年技术分水岭与软件行业变革
  • 3个关键步骤,如何用OpenRocket从零设计出稳定飞行的模型火箭?
  • League-Toolkit:英雄联盟终极自动化工具完整指南 - 基于LCU API的高效游戏助手解决方案
  • HarmonyOS 实战教程(四):首页布局实现 —— Swiper 轮播、Grid 网格与组件化 —— 以「柚兔自测量表」为例
  • huststore同步机制深度剖析:数据一致性与高吞吐量的平衡之道
  • DeepSeek V4 API成本优化:缓存策略与批量处理的工程实践
  • Type Theme博客文章撰写指南:Markdown语法与特色功能使用技巧
  • 2026 年至今,陕县热门的塑料光亮剂生产厂家有哪些,旧塑料喷一喷,居然能新得像刚出厂?这玩意儿到底藏了啥玄机?-稳定嘉 - 鉴选官
  • oneAPI Math Library (oneMath)扩展开发:如何添加自定义数学函数后端
  • 解决Embark.vim常见问题:真彩色显示与终端兼容性完全指南
  • 使命召唤18先锋学习版安装教程:从环境准备到故障排查
  • 旧衣回收按斤算吗?爱宝拉高价上门回收真香揭秘 - 快递物流资讯
  • 从Java后端到AI应用开发:33岁转型踩坑8年终悟,2026年收藏这3类人慎重转行!
  • 深入解析TI C2000 F2807x:实时控制MCU架构、外设与电机控制实战
  • huststore API完全指南:从基础操作到高级功能的全面解析
  • 英雄联盟Akari助手:重新定义你的游戏准备体验
  • AI辅助教材写作:降低查重率的实战技巧与工具链
  • 扣子测试用例机器人落地踩坑实录:从零部署到日均生成286条高覆盖用例,我用这5步避开了83%的失败陷阱