ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

鸿蒙 ArkTS 实战:侧滑菜单 SideBarContainer

鸿蒙 ArkTS 实战:侧滑菜单 SideBarContainer 引言在移动应用的导航体系中抽屉式菜单Drawer Navigation是最经典的导航模式之一。从最早的 Android 原生 Navigation Drawer到 Material Design 中规范的 Navigation Rail再到各平台对侧滑手势的原生支持抽屉导航以其「隐藏式面板 内容覆盖」的独特交互成为了承载多级菜单、用户中心、功能入口等场景的不二之选。HarmonyOS NEXT 提供了SideBarContainer组件以声明式的方式实现了抽屉导航支持 Overlay覆盖式和 Inline内联式两种展示模式。示例 91 以「我的菜单」为主题实现了一个左侧抽屉导航页面。用户点击「打开菜单」按钮左侧菜单栏会从左侧滑出覆盖在主内容区之上菜单项以列表形式排列支持选中高亮点击菜单项后菜单自动收起主内容区显示选中状态并通过promptAction.showToast弹出操作反馈。整个流程涉及SideBarContainer的状态绑定、菜单项的ForEach渲染、选中态的视觉反馈、以及onChange事件的双向同步几乎涵盖了抽屉导航实现的所有核心要点。这篇文章会严格按源码顺序先介绍应用的整体功能与布局结构再拆解SideBarContainer的核心属性与事件接着逐段解读.ets源码中的菜单渲染、选中逻辑、交互反馈然后分析 Overlay 模式与 Inline 模式的区别、showSideBar绑定机制、菜单 UI 的样式设计思路最后给出运行操作指南、可扩展方向与常见问题调试技巧。读完后你不仅能看懂这一个侧滑菜单页面还能举一反三把它应用到用户中心、功能导航、分类浏览等任何需要抽屉导航的场景。1. 应用概述与功能「侧滑菜单」是一个面向导航场景的工具型页面交互路径清晰点击打开菜单 → 查看菜单项 → 点击选中 → 自动收起。页面自上而下分为三块区域顶部是返回栏左侧「返回」按钮调用router.back()返回上一页中间是标题「侧滑菜单」中部是SideBarContainer容器左侧菜单栏占 40% 宽度深色背景#1f2733右侧主内容区占满剩余空间浅灰背景#f2f3f5底部功能说明卡片列出三条使用提示。1.1 核心功能清单抽屉式菜单展示使用SideBarContainer组件实现左侧抽屉菜单支持 Overlay 覆盖模式。菜单项高亮选中点击菜单项时选中项文字变蓝色#1a6cff、加粗、带半透明蓝色背景未选中项为灰色。自动收起点击菜单项后侧边栏自动收起给用户完整的主内容区操作空间。双向状态同步通过showSideBar属性和onChange回调实现菜单展开状态的双向绑定。操作反馈点击菜单项后通过promptAction.showToast弹出提示如「点击了首页」。功能说明卡片主内容区底部展示白色圆角卡片列出三条使用提示引导用户操作。1.2 技术要点一览整个示例用到的关键技术对「抽屉导航」类页面很有代表性SideBarContainer组件的 Overlay 模式、showSideBar状态绑定与onChange事件回调、菜单项列表的ForEach渲染与选中态判断、Text组件的动态样式绑定颜色、字重、背景色、以及Divider分隔线的使用。把这些要点串起来就构成了一条完整的「状态驱动 → UI 渲染 → 交互反馈 → 状态更新」的交互闭环。2. 核心知识点在逐段读代码之前先把侧滑菜单页面承载的 ArkTS 核心知识讲清楚。2.1 SideBarContainer 组件与 Overlay 模式SideBarContainer是 ArkUI 提供的抽屉容器组件用于实现「侧边栏 主内容区」的布局结构。它支持两种展示模式SideBarContainerType.Overlay覆盖模式侧边栏滑出时覆盖在主内容区之上主内容区不移动。这是最常见的抽屉效果适合移动端。SideBarContainerType.Inline内联模式侧边栏展开时主内容区被挤压侧边栏与主内容区并排显示适合平板或横屏场景。示例使用的是 Overlay 模式SideBarContainer(SideBarContainerType.Overlay){// 左侧菜单栏第一个子组件Column(){...}// 右侧主内容区第二个子组件Column(){...}}SideBarContainer接受一个类型参数和两个子组件第一个子组件是侧边栏内容第二个子组件是主内容区。组件内部会自动处理滑动手势和动画过渡。2.2 showSideBar 状态绑定与 onChange 回调SideBarContainer的展开/收起通过showSideBar属性控制而onChange回调则在侧边栏状态变化时触发SideBarContainer(SideBarContainerType.Overlay){// 子组件...}.showSideBar(this.show).onChange((v:boolean){this.showv;})这里涉及一个双向绑定的模式正向控制当this.show为true时侧边栏展开为false时收起。反向同步当用户通过手势滑动或点击外部区域使侧边栏收起时onChange回调被触发参数v会更新this.show的值。这个双向绑定确保了无论通过哪种方式改变侧边栏状态this.show都能保持同步。如果只使用showSideBar而不处理onChange那么用户手动收起菜单后this.show仍然是true下次点击按钮时就会出现状态不一致的问题。2.3 菜单项的动态样式绑定菜单项的选中态通过动态样式绑定实现Text(item).fontColor(this.selIdxidx?#1a6cff:#cccccc).fontWeight(this.selIdxidx?FontWeight.Bold:FontWeight.Normal).backgroundColor(this.selIdxidx?rgba(26,108,255,0.18):rgba(0,0,0,0))这是 ArkUI 中条件样式绑定的标准写法通过三元运算符根据this.selIdx与当前idx的比较结果动态决定fontColor、fontWeight、backgroundColor三个属性的值。选中项使用主题蓝色#1a6cff、加粗字重、半透明蓝色背景未选中项使用浅灰色#cccccc、正常字重、透明背景。这种方式比为选中项单独创建一个组件更简洁性能也更好。2.4 ForEach 渲染菜单列表菜单项通过ForEach组件从数组渲染ForEach(this.menus,(item:string,idx:number){Text(item).width(86%).height(52)// ... 其他属性.onClick((){this.chooseMenu(idx);})},(item:string,idx:number)idx.toString())ForEach的三个参数分别是数据源this.menus数组包含四个菜单项名称。渲染函数接收每个元素和索引返回对应的 UI 组件。这里返回的是一个带完整样式和点击事件的Text组件。键值生成器为每个元素生成唯一的 key用于 ArkUI 的 diff 算法。这里使用idx.toString()作为 key确保每个菜单项有稳定的标识。2.5 promptAction 轻提示promptAction是 ArkUI 提供的轻量级提示 API来自kit.ArkUIimport{promptAction}fromkit.ArkUI;promptAction.showToast({message:点击了this.menus[idx]});showToast会在屏幕底部弹出一个短消息持续约 2 秒后自动消失。它适用于不需要用户交互的简单提示比自定义的AlertDialog更轻量也不需要额外的状态管理。在侧滑菜单这种交互场景中promptAction是最合适的反馈方式。3. 源码逐段解析现在开始按源码顺序逐段解读index91.ets从导入声明到build方法完整展示侧滑菜单的实现细节。3.1 导入声明与组件声明import{router}fromkit.ArkUI;import{promptAction}fromkit.ArkUI;EntryComponentstruct Index91{源码开头导入了两个 ArkUI 模块router用于页面导航调用router.back()返回上一页promptAction用于轻提示反馈。Entry装饰器标记该组件为页面入口Component装饰器标记该结构体为可复用的 UI 组件。3.2 状态变量与菜单数据Stateshow:booleanfalse;StateselIdx:number0;privatemenus:string[][首页,消息,设置,关于];组件声明了两个State状态变量和一个私有数组show控制侧边栏的展开/收起初始为false收起状态。当用户点击「打开菜单」按钮或菜单项时这个值会被修改。selIdx记录当前选中的菜单项索引初始为0选中第一项「首页」。这个值驱动菜单项的高亮样式和主内容区的选中状态文本。menus菜单项名称数组包含四个导航入口。使用private修饰因为它不需要从外部访问。3.3 chooseMenu 选中处理方法privatechooseMenu(idx:number):void{this.selIdxidx;this.showfalse;promptAction.showToast({message:点击了this.menus[idx]});}chooseMenu是菜单项点击的处理函数接收一个参数idx选中的菜单项索引执行三个操作更新selIdx为点击的索引触发菜单项的高亮样式重新渲染。设置show为false自动收起侧边栏。这是侧滑菜单的标准交互——选中后自动关闭。通过promptAction.showToast弹出提示告知用户点击了哪个菜单项。这三个操作的顺序很重要先更新选中态再收起菜单最后弹出提示。如果先收起菜单再更新选中态在菜单收起的动画过程中用户可能看到短暂的旧选中状态。3.4 build 方法整体结构build方法构建了整个页面的 UI 结构最外层是一个Column包含顶部返回栏和SideBarContainer两部分build(){Column(){// 顶部返回栏Row(){...}// 侧滑菜单容器SideBarContainer(SideBarContainerType.Overlay){...}}.width(100%).height(100%).backgroundColor(#f2f3f5)}最外层Column设置为全屏宽高100%背景色为浅灰色#f2f3f5给整个页面一个统一的底色。3.5 顶部返回栏Row(){Button(返回).backgroundColor(#1a6cff).fontColor(Color.White).onClick((){router.back();})Text(侧滑菜单).fontSize(18).fontWeight(FontWeight.Bold)Blank()}.width(100%).padding({left:12,right:12,top:10,bottom:10})顶部返回栏是一个Row宽度占满整屏带内边距。从左到右依次是蓝色「返回」按钮点击调用router.back()、居中的标题文字「侧滑菜单」、右侧的Blank()弹性空白保证标题居中。Blank()是 ArkUI 中一个特殊的弹性空白组件它会占据Row中所有剩余空间。由于Blank()放在标题右侧它会把标题推到中间位置实现标题居中的效果。3.6 SideBarContainer 左侧菜单栏SideBarContainer是整个页面的核心它的第一个子组件是左侧菜单栏SideBarContainer(SideBarContainerType.Overlay){// 左侧菜单栏Column(){Text(我的菜单).fontSize(20).fontColor(Color.White).fontWeight(FontWeight.Bold).margin({top:24,bottom:20})Divider().color(#3a4657).strokeWidth(1).margin({bottom:10})ForEach(this.menus,(item:string,idx:number){Text(item).width(86%).height(52).fontSize(16).fontColor(this.selIdxidx?#1a6cff:#cccccc).fontWeight(this.selIdxidx?FontWeight.Bold:FontWeight.Normal).borderRadius(8).textAlign(TextAlign.Center).backgroundColor(this.selIdxidx?rgba(26,108,255,0.18):rgba(0,0,0,0)).margin({top:6}).onClick((){this.chooseMenu(idx);})},(item:string,idx:number)idx.toString())}.width(40%).height(100%).backgroundColor(#1f2733).padding({left:12,right:12,top:8})左侧菜单栏的结构分为三部分标题区白色大字「我的菜单」上下带外边距作为菜单的视觉起点。分隔线Divider组件在标题和菜单项之间画一条细线颜色为深灰色#3a4657与深色背景形成层次。菜单项列表通过ForEach渲染四个Text菜单项每项宽度 86%、高度 52vp、圆角 8、居中对齐。选中态用主题蓝#1a6cff文字 半透明蓝背景未选中态用浅灰#cccccc文字 透明背景。整个菜单栏宽度为屏幕的 40%高度 100%深色背景#1f2733带内边距。3.7 SideBarContainer 右侧主内容区SideBarContainer的第二个子组件是右侧主内容区// 右侧主内容区Column(){Text(主内容).fontSize(24).fontWeight(FontWeight.Bold).fontColor(#333333).margin({top:80})Text(当前选中this.menus[this.selIdx]).fontSize(14).fontColor(#888888).margin({top:12})Text(点击下方按钮打开侧滑菜单).fontSize(13).fontColor(#aaaaaa).margin({top:8})Button(打开菜单).width(180).height(46).backgroundColor(#1a6cff).fontColor(Color.White).margin({top:40}).onClick((){this.showtrue;})Column(){Text(功能说明).fontSize(16).fontWeight(FontWeight.Bold).fontColor(#333333)Divider().color(#eeeeee).margin({top:10,bottom:10})Text(1. 点击打开菜单展开左侧菜单).fontSize(13).fontColor(#666666).margin({bottom:6})Text(2. 点击菜单项可选中并自动收起).fontSize(13).fontColor(#666666).margin({bottom:6})Text(3. 点击空白区域或返回箭头也可收起).fontSize(13).fontColor(#666666)}.width(86%).padding(16).backgroundColor(#ffffff).borderRadius(12).margin({top:40})}.width(100%).height(100%).backgroundColor(#f2f3f5)主内容区从上到下依次包含标题区大号「主内容」标题 动态选中状态文本 操作提示文本垂直排列。打开菜单按钮蓝色主题按钮宽度 180vp、高度 46vp点击后设置this.show true展开侧边栏。功能说明卡片白色圆角卡片圆角 12标题「功能说明」下方带浅色分隔线列出三条使用提示每行间距 6vp。3.8 SideBarContainer 属性绑定最后是SideBarContainer的属性绑定部分.width(100%).layoutWeight(1).showSideBar(this.show).onChange((v:boolean){this.showv;})SideBarContainer设置为全宽100%、layoutWeight(1)占满剩余空间。showSideBar(this.show)绑定状态变量控制展开/收起onChange回调在侧边栏状态变化时同步更新this.show。layoutWeight(1)在这里非常关键——它确保SideBarContainer占据Column中除顶部返回栏之外的所有剩余空间实现自适应布局。如果不设置layoutWeightSideBarContainer的高度将由内容决定可能无法填满屏幕。4. 交互流程详解4.1 打开菜单流程用户点击「打开菜单」按钮触发以下流程按钮的onClick回调执行this.show true。State show的变化触发 ArkUI 的响应式更新机制。SideBarContainer检测到showSideBar属性变为true播放滑入动画展示左侧菜单栏。菜单栏从左侧滑出覆盖在主内容区之上。整个过程由 ArkUI 框架自动处理动画和手势开发者只需关注状态的变化。4.2 选中菜单项流程用户点击菜单项触发以下流程菜单项的onClick回调执行this.chooseMenu(idx)。chooseMenu方法更新this.selIdx为点击的索引。chooseMenu方法设置this.show false触发侧边栏收起动画。chooseMenu方法调用promptAction.showToast弹出提示。State selIdx的变化触发菜单项的样式重新渲染——选中项变蓝色加粗。主内容区的「当前选中」文本同步更新为新选中的菜单项名称。侧边栏收起完成后onChange回调被触发this.show被设为false实际上已经是false这一步确保状态一致。4.3 手势收起流程用户通过手势或点击菜单外部区域收起侧边栏时ArkUI 框架检测到收起手势开始收起动画。动画完成后onChange回调被触发参数v为false。this.show被更新为false与实际状态保持一致。如果没有onChange回调this.show仍然是true下次点击「打开菜单」按钮时由于showSideBar已经是true不会触发新的展开动画导致按钮失效。5. UI 样式设计思路5.1 深色侧边栏 浅色内容区示例采用了经典的「深色导航 浅色内容」配色方案侧边栏使用深色背景#1f2733白色文字营造出专业的导航氛围。主内容区使用浅灰色背景#f2f3f5黑色文字内容区域清晰可读。选中态使用主题蓝#1a6cff在深色和浅色背景上都有良好的视觉效果。这种配色方案的优点是导航区和内容区层次分明用户可以快速区分两种功能区域。5.2 选中态视觉反馈选中态通过三重视觉效果区分文字颜色从浅灰色#cccccc变为主题蓝#1a6cff。字重从FontWeight.Normal变为FontWeight.Bold。背景色从透明变为半透明蓝色rgba(26,108,255,0.18)。三重效果叠加确保选中项在任何背景下都有清晰的视觉反馈。5.3 卡片式布局主内容区的功能说明卡片采用卡片式设计白色背景#ffffff与页面浅灰色背景形成对比。圆角 12vp视觉柔和。宽度 86%左右留足边距。内边距 16vp内容不拥挤。卡片式布局在移动端应用中非常常见它通过边框、圆角和阴影此示例未添加阴影将相关信息聚合在一起提升了页面的层次感。6. 运行与测试6.1 运行步骤使用 DevEco Studio 打开项目。运行项目到模拟器或真机。在首页找到「侧滑菜单」示例入口点击进入。点击「打开菜单」按钮观察侧边栏滑出效果。点击任意菜单项观察选中高亮、自动收起、Toast 提示效果。6.2 测试场景测试场景预期结果点击「打开菜单」按钮侧边栏从左侧滑出点击菜单项「首页」菜单项高亮、侧边栏收起、Toast 显示「点击了首页」点击菜单项「设置」菜单项高亮变为「设置」、主内容区文本更新点击菜单外部区域侧边栏收起this.show更新为false连续快速点击菜单项每次都正确切换选中态和收起菜单7. 可扩展方向7.1 Inline 模式适配将SideBarContainerType.Overlay改为SideBarContainerType.Inline即可实现内联模式侧边栏与主内容区并排显示。适合平板或横屏场景可以通过屏幕宽度动态切换模式。7.2 多级菜单当前示例只有一级菜单可以扩展为多级菜单结构。点击一级菜单项展开二级子菜单使用ForEach嵌套渲染配合动画效果实现平滑的折叠展开。7.3 菜单图标为每个菜单项添加图标使用Row布局 Image/Text组件组合。图标可以使用系统内置图标或自定义资源提升菜单的视觉辨识度。7.4 路由导航将菜单项与路由绑定点击菜单项不仅更新选中态还跳转到对应的页面。可以使用router.pushUrl或router.replaceUrl实现页面导航构建完整的应用导航体系。7.5 持久化选中状态使用Preferences存储用户最后选中的菜单项下次进入页面时自动高亮上次选中的项提供个性化的用户体验。8. 常见问题与调试8.1 侧边栏无法通过按钮打开问题点击「打开菜单」按钮后侧边栏没有展开。排查检查show状态是否正确更新——在onClick回调中添加console.log(this.show)确认。检查showSideBar(this.show)属性绑定是否正确。确认没有在其他地方重置this.show的值。8.2 手势收起后按钮失效问题手动滑动收起侧边栏后再次点击「打开菜单」按钮无效。排查确认onChange回调是否正确设置。没有回调时this.show在手势收起后仍为true导致按钮无法触发新的展开。在onChange回调中添加日志确认回调是否被触发。8.3 菜单项样式不更新问题点击菜单项后选中项的高亮样式没有更新。排查确认selIdx是否正确更新——在chooseMenu中添加日志。检查ForEach的键值生成器是否稳定。如果 key 不稳定ArkUI 可能无法正确 diff 和重新渲染。确认条件表达式this.selIdx idx是否正确——注意类型比较selIdx是numberidx也是number类型一致。8.4 布局错乱问题SideBarContainer没有正确占满屏幕剩余空间。排查确认SideBarContainer设置了.layoutWeight(1)这是自适应布局的关键。检查父容器Column的高度是否为100%。确认顶部返回栏的高度是固定的不会影响剩余空间的计算。9. 技术总结示例 91 的侧滑菜单虽然代码量不大但涉及了SideBarContainer的核心用法、状态绑定与双向同步、动态样式绑定、列表渲染等多个 ArkUI 关键知识点。通过这个示例我们可以总结出抽屉导航的实现范式状态驱动用一个State boolean变量控制侧边栏的展开/收起。双向同步同时使用showSideBar属性和onChange回调确保状态与 UI 始终一致。动态样式用三元表达式根据选中索引动态计算组件样式避免创建额外组件。即时反馈用promptAction.showToast提供轻量级的操作反馈。掌握了这些范式后就可以轻松地将其扩展到多级菜单、路由导航、用户中心等更复杂的场景中。侧滑导航作为移动端应用的基础导航模式值得每个鸿蒙开发者深入学习和实践。
返回列表