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

第20篇|底部导航:地图、拍照、相册、保险箱的产品路径

第20篇|底部导航:地图、拍照、相册、保险箱的产品路径

底部导航看起来只是四个入口,但在一个相机类应用里,它实际定义了产品路径:从「在哪里拍」进入地图,从「马上拍」进入相机,从「拍完看」进入相册,从「私密内容」进入保险箱。导航如果只做成按钮,就会漏掉状态、权限和内容边界。

本篇对应源码仍然是entry/src/main/ets/pages/Index.ets,重点看buildBottomNavigation()buildNavItem()buildNavIconMark()

四个入口不是四个普通按钮

项目里的底部导航是这样组织的:

Row() { this.buildNavItem('地图', 'map') this.buildNavItem('拍照', 'camera') this.buildNavItem('相册', 'gallery') this.buildNavItem('保险箱', 'vault') }

每个入口都走同一个buildNavItem(label, tab),这样选中态、字体、边框、光效、点击行为可以统一维护。统一并不等于行为完全一样,gallery的点击会走openFullGalleryFromNavigation(),其他入口走switchTab(tab)。这是一个很小但重要的产品判断:相册不是普通页签,它要进入完整浏览路径。

为什么导航层要透明命中

地图页底部覆盖层代码里有一段容易被忽略:

Column({ space: 14 }) { if (this.getMapPhotoDockMemories().length > 0) { this.buildMapPhotoGroupDock() } this.buildBottomNavigation() } .hitTestBehavior(HitTestMode.Transparent)

它的意思是:容器空白区域不吃掉手势,真正的卡片和按钮才响应点击。这样用户在底部附近仍然能拖动地图,不会感觉地图「死掉了一块」。这比单纯调zIndex更可靠,因为问题不在层级,而在命中区域。

选中态为什么要同时改图标、边框和光效

buildNavIconMark()使用资源命名来区分默认态和选中态:

Image(this.isActiveTab(tab) ? $r('app.media.nav_camera_active') : $r('app.media.nav_camera'))

再配合ml_selected_glassgetNavGlowColor(tab)hdsEffect.HdsEffectBuilder().pointLight(...),选中态会同时体现在图标、背景、边框和光效上。官方 UIDesignKit 文档提供了hdsEffectHdsEffectBuilder,项目里用它做导航玻璃层的光照反馈,而不是只把文字变粗。

和侧边导航的关系

buildBottomNavigation()的第一句是:

if (this.shouldUseSideNavigation()) { Blank().width(0).height(0) } else { // 构建底部导航 }

这说明底部导航只服务手机形态。宽度达到平板/2in1 条件后,主入口交给侧边导航。这个判断避免了一个常见问题:大屏上同时出现底部导航和侧边导航,路径重复,空间也浪费。

自测建议

  1. 在地图页拖动底图,确认底部透明区域不阻断地图手势。
  2. 依次点击地图、拍照、相册、保险箱,确认选中态和页面内容一致。
  3. 点击相册入口,确认走完整相册路径,而不是只切普通 Tab。
  4. 把窗口宽度调到 600vp 以上,确认底部导航消失、侧边导航出现。
  5. 切深色模式,确认ml_nav_glassml_selected_glass、文字色和图标仍然可读。

导航行为不是一个 switch 就结束

底部导航的点击分支看起来很短,但背后有清楚的产品语义:

.onClick(() => { if (tab === 'gallery') { this.openFullGalleryFromNavigation(); return; } this.switchTab(tab); })

mapcameravault是主 Tab 切换,gallery是完整浏览路径。这样设计是因为相册页不仅展示缩略图,还承担大图查看、筛选、回看和返回逻辑。如果相册也只做switchTab('gallery'),用户从首页进入后会丢失“完整浏览”的上下文,后续文章讲相册详情时就会发现入口不一致。

视觉状态的四个来源

一个导航项的选中态由四部分组成,不是单独靠颜色:

来源代码位置作用
图标资源buildNavIconMark(tab)默认态和_active成对切换
玻璃背景ml_selected_glass让当前入口有稳定承托面
边框和阴影getNavGlowColor(tab)区分不同业务入口的强调色
光照效果hdsEffect.HdsEffectBuilder()让玻璃层有系统级质感

官方hdsEffect文档提供的是效果能力,项目里没有把它当成装饰堆叠,而是只在导航容器和选中项上使用。这样做的好处是光效有明确语义:它只强调“你现在在哪个路径里”。

代码验证 1:底部导航只在手机形态出现

buildBottomNavigation()开头直接判断侧边导航:

if (this.shouldUseSideNavigation()) { Blank() .width(0) .height(0) } else { // 构建底部导航 }

这段代码可以用窗口宽度验证。把预览器或真机窗口拖到 600vp 以上,底部导航应该消失;再缩回手机宽度,它应该重新出现。这个判断比在 CSS 或样式里隐藏某个容器更可靠,因为它从构建阶段就不再输出底部导航,避免大屏上出现两个主入口。

代码验证 2:资源成对存在

第 20 篇用到的导航资源必须成对存在,否则选中态会断。可以在项目根目录运行:

Get-ChildItem entry/src/main/resources/base/media -File | Where-Object { $_.Name -like 'nav_*' } | Sort-Object Name

应该能看到nav_map.pngnav_map_active.pngnav_camera.pngnav_camera_active.pngnav_gallery.pngnav_gallery_active.pngnav_vault.pngnav_vault_active.png。这就是官方资源访问文档里“通过资源文件管理媒体资源”的落地方式:代码只写$r('app.media.nav_camera'),真正替换视觉时改资源文件,不改导航逻辑。

可复用检查清单

如果你也在做相机、地图或工具类应用,可以按下面顺序检查底部导航:

  1. 先确认每个入口是否代表不同任务,而不是仅仅分页面。
  2. 再确认特殊路径是否单独处理,例如本文的相册入口。
  3. 然后检查命中区域,容器空白不要吞掉地图或内容手势。
  4. 最后检查大屏降级,底部导航和侧边导航不要同时存在。

这套顺序比先画 UI 更稳,因为它先确定“入口要完成什么任务”,再决定“入口长什么样”。

小结

一个高质量导航,不只是能点。它要表达当前所在位置,要把不同业务路径分开,还要在地图这种强交互背景上处理好命中区域。这里的实现把「路径统一」和「行为差异」放在同一层:UI 统一由buildNavItem()承担,特殊路径由点击分支承担,设备差异由shouldUseSideNavigation()承担。

参考依据:

  • 华为开发者文档《hdsEffect》:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ui-design-hdseffect
  • 华为开发者文档《资源分类与访问》:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/resource-categories-and-access
  • 项目源码:entry/src/main/ets/pages/Index.ets
http://www.rkmt.cn/news/1424353.html

相关文章:

  • 2026年Q2不锈钢景墙厂家评测:不锈钢幕墙、不锈钢装饰线条、北京铝板廊架、园林景观廊架、幕墙铝板、玻璃栏杆、车库玻璃雨棚选择指南 - 优质品牌商家
  • 字符串之Hash
  • 终极指南:在Linux系统下无缝访问BitLocker加密分区的完整方案
  • PEExplorerV2深度解析:如何用三窗格架构解密Windows可执行文件内部秘密?
  • 第21篇|侧边导航:平板和 2in1 为什么不照搬手机布局
  • 【原创解锁】15日天气预报 解锁会员 精准预警超好用
  • C++跨平台开发:微信聊天记录导出工具架构解析与实现
  • 挖坑指南:为什么你的数据采集卡老是“丢帧”?一篇文章讲透Flash、FRAM、PSRAM的区别与实战
  • 三步轻松复活经典游戏联机:IPXWrapper让老游戏重获新生
  • 别再瞎测了!用IxChariot给工业网关做吞吐量测试,这5个坑我帮你踩过了
  • Photoshop AVIF插件深度探索:为什么这款开源神器正在改变图像处理工作流?
  • 别再重装系统了!LightDM报错‘Failed to Start’的5种修复方案与深度解析
  • Flutter Hero Animation 详解
  • 2026年Q2北京铝合金回收:北京溴化锂机组回收/北京电器回收/北京电子设备回收/北京电池回收/北京电线电缆回收/选择指南 - 优质品牌商家
  • 【图像提取】基于数学形态学的数字视网膜图像血管提取 (DRIVE) 数据集分割附Matlab代码
  • 【AI搜索革命性差异指南】:3大核心维度拆解AI搜索与传统搜索的底层逻辑差异
  • 【绿化】Fong投屏 一键手机投屏 多设备兼容超稳定
  • 深入Windows消息循环:手把手教你用Unity拦截WM_SIZING实现自定义窗口控制
  • 如何选择工程信息平台?2026年5月推荐口碑好的服务项目人脉难寻痛点 - 品牌推荐
  • 5分钟终结VC运行库安装难题:一站式解决方案深度解析
  • Lindy内容创作自动化:从零搭建抗衰减内容引擎的4层架构,含GitHub开源模板
  • Linux系统终极解决方案:Dislocker轻松访问BitLocker加密分区
  • AMBA 总线接口访问明细
  • Agent赋能下药物警戒自动生成的个例报告符合监管要求吗?深度拆解AI Agent在PV领域的合规边界
  • 178、运动控制中的行业标准:功能安全IEC 61508
  • 技术人的个人理财:从入门到精通
  • 微信聊天记录永久保存完整指南:WeChatExporter开源工具使用教程
  • 从零开发游戏需要学习的c#模块,第三十一章(技能冷却系统 —— 范围爆炸)
  • DroidCam OBS插件终极指南:让手机摄像头快速变身高清直播源
  • 3个核心功能彻底解决Windows C盘爆红问题:开源工具Windows Cleaner深度解析