HarmonyOs应用《重要日》开发第8篇 - 主页面布局与 Tab 导航实现 本篇深入讲解 ImportantDays 的主入口页面 MainEntry包括 Navigation 容器、Tabs 底部导航、全屏沉浸式布局以及 Tab 栏的自定义实现。一、MainEntry 页面概述MainEntry是应用的入口页面使用Entry装饰器标记。它包含一个底部 Tab 导航三个 Tab 分别对应三个主页面┌─────────────────────────────┐ │ │ │ Tab 1: 重要日列表 │ │ (ImportantDayListPage) │ │ │ ├─────────────────────────────┤ │ 重要日 | 日历 | 我的 │ └─────────────────────────────┘二、完整代码分析2.1 页面结构// pages/MainEntry.etsimport{AppStorageV2}fromkit.ArkUI;import{AppConstants}from../common/Constants;import{TAB_LIST}from../common/TabList;import{TabListItem}from../types/Types;import{AvoidArea}from../model/AvoidArea;import{MainViewModel}from../viewmodel/MainViewModel;import{ImportantDayListPage}from./ImportantDayListPage;import{CalendarPage}from./CalendarPage;import{MinePage}from./MinePage;EntryComponentV2struct MainEntry{privatevm:MainViewModelMainViewModel.instance;LocalavoidArea:AvoidAreaAppStorageV2.connect(AvoidArea,()newAvoidArea(0,0))!;build(){Navigation(){Column(){Tabs({barPosition:BarPosition.End,index:this.vm.curTabIndex}){TabContent(){ImportantDayListPage()}.tabBar(this.tabBarBuilder(TAB_LIST[0],0));TabContent(){CalendarPage()}.tabBar(this.tabBarBuilder(TAB_LIST[1],1));TabContent(){MinePage()}.tabBar(this.tabBarBuilder(TAB_LIST[2],2));}.scrollable(false).height(AppConstants.FULL_HEIGHT).animationDuration(0).barMode(BarMode.Fixed).onChange((index:number){this.vm.curTabIndexindex;})}.width(AppConstants.FULL_WIDTH).height(AppConstants.FULL_HEIGHT).backgroundColor($r(sys.color.background_primary)).padding({bottom:px2vp(this.avoidArea.bottomRectHeight)})}.height(AppConstants.FULL_HEIGHT).width(AppConstants.FULL_WIDTH).hideTitleBar(true).hideToolBar(true).hideBackButton(true).mode(NavigationMode.Stack)}BuildertabBarBuilder(item:TabListItem,index:number){Column(){Image(this.vm.curTabIndexindex?item.iconChecked:item.icon).width(24).height(24)Text(item.label).fontColor(this.vm.curTabIndexindex?$r(app.color.icon_checked):$r(app.color.font_secondary)).fontSize($r(app.string.font_size_10)).margin({top:$r(app.string.margin_xs)});}.width(AppConstants.FULL_WIDTH);}}2.2 关键设计点Navigation 容器Navigation(){// 内容}.mode(NavigationMode.Stack).hideTitleBar(true).hideToolBar(true).hideBackButton(true)使用Navigation作为根容器设置为 Stack 模式。隐藏了 Navigation 自带的标题栏、工具栏和返回按钮因为本项目使用自定义的 Tab 导航和页面标题。Navigation 的作用是提供路由栈管理子页面AddEditDayPage、DayDetailPage通过router.pushUrl跳转时会压入栈中。Tabs 组件Tabs({barPosition:BarPosition.End,index:this.vm.curTabIndex}){// ...}.scrollable(false).animationDuration(0).barMode(BarMode.Fixed).onChange((index:number){this.vm.curTabIndexindex;})关键配置barPosition: BarPosition.EndTab 栏在底部index: this.vm.curTabIndex绑定当前选中索引到 ViewModelscrollable(false)禁止左右滑动切换 Tab避免与日历页的 Swiper 滑动冲突animationDuration(0)取消切换动画响应更迅速barMode(BarMode.Fixed)Tab 栏固定不滚动全屏沉浸式布局LocalavoidArea:AvoidAreaAppStorageV2.connect(AvoidArea,()newAvoidArea(0,0))!;// 在布局中.padding({bottom:px2vp(this.avoidArea.bottomRectHeight)})avoidArea.bottomRectHeight是底部导航指示器的高度。通过px2vp转换为 vp 单位后作为底部 padding确保内容不被导航指示器遮挡。Tab 栏自定义BuildertabBarBuilder(item:TabListItem,index:number){Column(){Image(this.vm.curTabIndexindex?item.iconChecked:item.icon).width(24).height(24)Text(item.label).fontColor(this.vm.curTabIndexindex?$r(app.color.icon_checked):$r(app.color.font_secondary)).fontSize($r(app.string.font_size_10)).margin({top:$r(app.string.margin_xs)});}.width(AppConstants.FULL_WIDTH);}自定义 Tab 栏包含图标和文字选中时使用iconChecked图标和icon_checked颜色蓝色未选中时使用icon图标和font_secondary颜色灰色图标 24x24文字 10fp三、Tab 配置3.1 TabList 定义// common/TabList.etsimport{TabListItem}from../types/Types;exportconstTAB_LIST:TabListItem[][{label:$r(app.string.tab_important_days),icon:$r(app.media.days_unchecked),iconChecked:$r(app.media.days_checked),},{label:$r(app.string.tab_calendar),icon:$r(app.media.calendar_unchecked),iconChecked:$r(app.media.calendar_checked),},{label:$r(app.string.tab_mine),icon:$r(app.media.mine_unchecked),iconChecked:$r(app.media.mine_checked),},];3.2 资源引用Tab 的文字标签使用资源引用$r(app.string.xxx)而非硬编码字符串// string.json{name:tab_important_days,value:重要日},{name:tab_calendar,value:日历},{name:tab_mine,value:我的}这种方式支持国际化——只需要添加其他语言的element/string.json即可。3.3 图标资源每个 Tab 有两个图标选中/未选中放在resources/base/media/目录下days_checked.png/days_unchecked.pngcalendar_checked.png/calendar_unchecked.pngmine_checked.png/mine_unchecked.png四、Tab 切换的状态管理4.1 ViewModel 中存储 Tab 索引// MainViewModelTracecurTabIndex:number0;Tab 索引存储在 ViewModel 中这样即使页面被销毁重建当前 Tab 也能恢复。4.2 双向同步// Tabs 的 index 属性Tabs({index:this.vm.curTabIndex})// onChange 回调.onChange((index:number){this.vm.curTabIndexindex;})ViewModel → Tabs当curTabIndex变化时Tabs 组件自动切换Tabs → ViewModel用户手动切换 Tab 时更新curTabIndex五、子页面的安全区域处理每个子页面都需要处理顶部安全区域状态栏// ImportantDayListPageRow(){Text(重要日).fontSize($r(app.float.title_font_size)).fontColor($r(app.color.font_primary)).fontWeight(FontWeight.Bold);}.width(100%).height(56).padding({left:20,right:20}).padding({top:px2vp(this.avoidArea.topRectHeight)});// 顶部安全区域avoidArea.topRectHeight是状态栏高度通过px2vp转换后作为顶部 padding。六、Navigation 路由栈6.1 页面跳转// 从列表页跳转到详情页router.pushUrl({url:pages/DayDetailPage});// 从列表页跳转到添加页router.pushUrl({url:pages/AddEditDayPage});// 返回上一页router.back();6.2 路由栈结构MainEntry (Tab 容器) ├── ImportantDayListPage (Tab 1) │ ├── → DayDetailPage (详情) │ │ └── → AddEditDayPage (编辑) │ └── → AddEditDayPage (添加) ├── CalendarPage (Tab 2) │ └── → DayDetailPage (详情) └── MinePage (Tab 3)router.pushUrl将页面压入栈中router.back()弹出栈顶页面。Navigation 的 Stack 模式管理这个栈。七、scrollable(false) 的重要性Tabs(...).scrollable(false)// 禁止滑动切换这个配置很重要。日历页面内部有一个 Swiper 实现的无限滚动日历如果 Tabs 也支持滑动切换用户在日历上左右滑动时会误触发 Tab 切换。设置scrollable(false)后只能通过点击 Tab 栏切换。八、性能考虑8.1 TabContent 懒加载ArkUI 的 Tabs 组件默认只渲染当前选中的 TabContent。当用户切换到某个 Tab 时该 Tab 的内容才会被创建和渲染。这减少了初始渲染的开销。8.2 避免不必要的重建由于三个子页面都以组件形式嵌入 TabContent它们的生命周期与 Tabs 组件一致。切换 Tab 不会销毁和重建子页面只是显示/隐藏。九、小结MainEntry 作为应用入口通过 Navigation Tabs 的组合实现了底部三 Tab 导航架构。沉浸式全屏布局通过 AvoidArea 模型统一管理安全区域。Tab 栏的自定义 Builder 实现了图标文字的双行布局。

相关新闻

最新新闻

Inno Setup多语言配置实战:从界面翻译到运行时语言切换

Inno Setup多语言配置实战:从界面翻译到运行时语言切换

1. Inno Setup多语言配置的核心价值 当你开发的软件需要面向全球用户时,安装包的多语言支持就成为了必备功能。想象一下,一个日本用户打开全是中文的安装界面,或者德国用户面对英文安装指引时的困惑——这些体验细节往往决定了用户对产品的第…

2026/7/16 5:40:33
智谱清言可以生成excel吗?AI导出鸭解锁高效导出新解法:

智谱清言可以生成excel吗?AI导出鸭解锁高效导出新解法:

《智谱清言可以生成excel吗?AI导出鸭给出实操答案》《智谱清言可以生成excel吗?AI导出鸭解锁高效导出新解法》 正文 在AI工具深度渗透办公场景的当下,“智谱清言可以生成excel吗”成为不少职场人、内容创作者的核心疑问。智谱清言作为主流AI模…

2026/7/16 5:40:33
接口测试课程2

接口测试课程2

接口测试流程1.接口用例设计与评审-> 2.接口调试-> 3.接口测试-> 4.回归测试-> 5.缺陷跟踪-> 6测试总结单接口用例设计有参数的接口要充分考虑到有什么输入规则,还要在这些规则的基础上划分出正向场景和逆向场景提取测试点,再根据提…

2026/7/16 5:40:33
VM深度学习

VM深度学习

海康威视 VisionMaster (VM) 的深度学习功能使用流程主要分为模型训练和方案部署两大阶段:第一阶段:模型训练(使用 VisionTrain 工具)最低硬件配置要求:操作系统:Windows 7 / Windows 10(64位中…

2026/7/16 5:40:33
生产级异步工具:用 async def 打造高性能 Agent

生产级异步工具:用 async def 打造高性能 Agent

💡 摘要:当 Agent 需要调用外部 API、查询数据库时,同步工具会阻塞整个事件循环。本文教你用 async def 编写生产级异步工具,实现并发执行、结构化错误处理和优雅降级,让 Agent 性能提升数倍。引言 你有没有遇到过这样…

2026/7/16 5:40:33
Agent工程化三支柱:MCP协议、SKILLS封装与Context Engine

Agent工程化三支柱:MCP协议、SKILLS封装与Context Engine

1. 项目概述:为什么“从零到一,再到可落地”是Agent开发最真实的写照我带过六支AI工程团队,亲手交付过17个上线运行超一年的Agent系统,从银行智能风控助手、制造业设备预测性维护Agent,到政务热线意图识别中台——所有…

2026/7/16 5:35:32

月新闻