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

HarmonyOS 应用开发《掌上英语》第54篇:设置页面全解析——从主题选择到数据清除

设置页面全解析——从主题选择到数据清除

引言

设置页面是每个应用都不可或缺的"控制中心",它汇聚了用户偏好配置、账户管理、应用信息等关键功能。一个设计良好的设置页面应当做到:功能分类清晰、交互反馈即时、配置项可持久化。本文将以SetUpPage为例,深入解析其在 HarmonyOS 上的完整实现。

SetUpPage位于features/minePage模块的views/SetupPage.ets中,是"我的"模块中的核心页面之一。它通过@Builder函数SetUpPageBuilder导出,注册在路由表中供全局导航使用。

设置项的模型设计

每个设置项对应一个SetupItem模型:

@ObservedV2exportclassSetupItem{@Tracemsg:string// 设置项标题@Traceicon:ResourceStr// 右侧图标@Tracecache?:string// 缓存大小(仅"清除缓存"项使用)@Traceurl?:string// 点击跳转的目标路由}

SetupItem使用@ObservedV2@Trace装饰器,保证属性的变化(如缓存大小的动态更新)能自动触发 UI 重绘。cache字段为可选字段,只有缓存相关的设置项才会使用;url字段绑定路由标识,使得设置项的点击行为可以通过数据驱动而非硬编码。

设置项列表的实现

列表数据初始化

设置项列表在组件内部直接定义:

@LocalsetupList:SetupItem[]=[newSetupItem('个人信息',$r('app.media.iconRight'),'',RouterMap.PERSONAL_CENTER_PAGE),newSetupItem('夜间模式',$r('app.media.iconRight'),'',''),newSetupItem('学习计划',$r('app.media.iconRight'),'','LearningPlanSettingPage'),newSetupItem('学习提醒',$r('app.media.iconRight'),'','ReminderSettingPage'),newSetupItem('隐私协议',$r('app.media.iconRight'),'','PrivacyStatementPage'),newSetupItem('关于',$r('app.media.iconRight'),'',RouterMap.ABOUT_PAGE),newSetupItem('清除缓存',$r('app.media.iconRight'),'0.0M',''),];

这里涉及的路由标识既有RouterMap枚举值(如RouterMap.PERSONAL_CENTER_PAGE),也有直接字符串(如'LearningPlanSettingPage')。使用RouterMap枚举的好处是编译期类型检查,避免字符串拼写错误;而直接使用字符串则更为灵活,适用于尚未纳入枚举的路由。

UI 渲染

每个设置项由SetupComponent组件渲染:

struct SetupComponent{@Param@RequiresetupItem:SetupItem;@Param@RequireselectItem:string='跟随系统';build(){Stack(){Row(){Text(this.setupItem.msg).fontColor($r('sys.color.font_primary')).fontSize($r('sys.float.Body_L'));Row(){if(this.setupItem.cache){Text(this.setupItem.cache)// 显示缓存大小.fontColor($r('sys.color.font_primary')).fontWeight(FontWeight.Medium)}Image(this.setupItem.icon)// 右侧箭头图标}}.width('100%').backgroundColor($r('sys.color.comp_background_list_card')).borderRadius($r('app.float.vp_16')).justifyContent(FlexAlign.SpaceBetween)}}}

组件采用左右布局:左侧是设置项标题文本,右侧是缓存数值(如有)加箭头图标。justifyContent(FlexAlign.SpaceBetween)保证左右内容自动撑开两端对齐。

点击事件分发

外层通过ForEach循环为每个设置项绑定点击事件:

ForEach(this.setupList,(item:SetupItem)=>{SetupComponent({...}).onClick(()=>{if(item.msg==='清除缓存'){this.showAlert(AlertType.clean);}elseif(item.msg==='夜间模式'){this.darkDialog.open();}elseif(item.msg==='个人信息'){if(item.url&&this.logoUser.isLogin){RouterModule.push({url:item.url});}else{RouterModule.push({url:RouterMap.LOGIN_PAGE,param:false});}}else{if(item.url){RouterModule.push({url:item.url});}}})})

事件分发策略是:特殊项(清除缓存、夜间模式)弹出对话框,个人信息项需要检查登录状态,其余常规项直接通过RouterModule.push导航。这种"数据驱动 + 特殊判断"的混合模式,在保持代码简洁的同时也覆盖了页面特有的交互逻辑。

夜间模式切换

夜间模式是设置页面的核心功能之一,实现涉及三个层面:UI 交互、系统 API 调用和偏好持久化。

选择弹窗

夜间模式的设置通过DarkColorDialog自定义弹窗实现:

@CustomDialogexportstruct DarkColorDialog{selectItem:string='';selectItemBack:(selectItem:string)=>void=()=>{};cancel:()=>void=()=>{};}

弹窗内使用 Grid 布局展示三个选项:跟随系统普通模式夜间模式。每个选项左侧显示文字,右侧显示选中标记:

Row(){Text(item.label)Image(item.label===this.selectItem?$r('app.media.icon_Checked'):$r('app.media.icon_ans_common'))}

当前选中的选项显示勾选图标(icon_Checked),未选中的显示普通圆形图标(icon_ans_common),视觉对比清晰。

模式切换逻辑

当用户选择某个模式后,SetUpPagehandleDark方法被调用:

handleDark(item:string){letcolorMode:number=1;if(item==='跟随系统'){colorMode=-1;this.getUIContext()?.getHostContext()?.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);}elseif(item==='普通模式'){colorMode=1;this.getUIContext()?.getHostContext()?.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);}else{colorMode=0;this.getUIContext()?.getHostContext()?.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_DARK);}PreferenceUtil.getInstance().put(PreferConstant.COLOR_MODE,colorMode);}

核心是调用ApplicationContext.setColorMode()方法设置主题模式,该方法接受ConfigurationConstant.ColorMode枚举值:

  • COLOR_MODE_NOT_SET(-1):跟随系统
  • COLOR_MODE_LIGHT(1):浅色模式
  • COLOR_MODE_DARK(0):深色模式

设置完成后,通过PreferenceUtil将选择持久化到首选项文件中。下次应用启动时,aboutToAppear会读取该值并恢复:

aboutToAppear():void{letcolorMode=PreferenceUtil.getInstance().get(PreferConstant.COLOR_MODE,-1)asnumber;this.selectItem=this.getColorItem(colorMode);}

getColorItem方法将数字映射为对应的描述字符串,完成从存储到展示的闭环。

缓存清除

缓存清除是典型的"风险操作",需要谨慎确认后再执行。SetUpPage通过两步确认机制实现:先弹框确认,再执行清除。

确认弹框

使用系统级showAlertDialogAPI:

showAlert(type:AlertType){this.getUIContext().showAlertDialog({message:type===AlertType.clean?'请确认是否清除缓存':'确定要退出登录吗',autoCancel:false,buttons:[{value:'取消',action:()=>{}},{value:'确定',action:()=>{if(type===AlertType.clean)this.clean();elsethis.loginOut();}}]});}

AlertType枚举区分"清除缓存"和"退出登录"两种弹框类型,共享同一个弹框方法但展示不同的文案和执行逻辑。

缓存大小读取

在页面初始化时,通过storageStatistics.getCurrentBundleStats获取应用的存储统计数据:

getClearSize(){storageStatistics.getCurrentBundleStats((error,bundleStats)=>{this.setupList.forEach(eme=>{if(eme.msg==='清除缓存'){letisClean=PreferenceUtil.getInstance().isClean()&&PreferenceUtil.getInstance(PreferConstant.TOPIC_NOTES).isClean();if(isClean){eme.cache='0KB';}else{eme.cache=(bundleStats.dataSize/1024).toFixed(2)+'KB';}}});});}

这里有一个巧妙的设计:通过PreferenceUtilisClean()方法判断是否已经执行过清除。如果两个首选项实例均为初始状态(未写入过任何数据),则直接显示0KB,否则从bundleStats.dataSize计算真实缓存大小。

执行清除

clean方法的清除策略涉及多个目录:

asyncclean(){letpaths:Array<string>=[];letcontext=this.getUIContext()?.getHostContext()!;letmoduleContext=awaitapplication.createModuleContext(context,'entry');// 收集需要清除的目录paths.push(moduleContext.cacheDir);paths.push(context.cacheDir);paths.push(moduleContext.preferencesDir);paths.push(context.preferencesDir);// EL1 加密区域的 cache 和 preferences 目录moduleContext.area=contextConstant.AreaMode.EL1;context.area=contextConstant.AreaMode.EL1;paths.push(moduleContext.cacheDir);paths.push(context.cacheDir);paths.push(moduleContext.preferencesDir);paths.push(context.preferencesDir);// 清除所有 PreferenceUtil 的数据PreferenceUtil.getInstance().clear();PreferenceUtil.getInstance(PreferConstant.TOPIC_NOTES).clear();// 逐文件删除for(letpathofpaths){letfilenames=awaitfileIo.listFile(path);for(letfilenameoffilenames){letdirPath=path+'/'+filename;letisDirectory=fileIo.statSync(dirPath).isDirectory();if(isDirectory){fileIo.unlinkSync(dirPath);// 目录用同步删除}else{fileIo.unlink(dirPath);// 文件用异步删除}}}this.getClearSize();// 重新计算缓存大小}

清除范围覆盖了主工程模块和 entry 模块的cacheDirpreferencesDir,同时针对 EL1(加密等级 1)区域也进行了清除。对于目录使用unlinkSync同步删除,对于文件使用unlink异步删除——这种差异化处理既避免了异步删除目录可能引发的并发问题,又利用异步删除提升文件删除效率。最后重新调用getClearSize()刷新 UI 上的缓存数值。

隐私协议与关于页面

对于隐私协议这类静态展示页面,SetUpPage通过路由跳转的方式将它们分发到各自的独立页面。路由表中注册了多个相关页面:

  • PrivacyStatementPage:隐私声明
  • PrivacyAgreementBuilder:隐私协议
  • PrivacyUseAlertBuilder:隐私使用说明
  • AboutPage:关于页面(展示应用名称、版本号、图标等信息)
  • FeedbackSubmitPage:意见反馈页面

这些页面通过RouterMap统一管理,在设置项中按需引用。

退出登录

退出登录位于设置列表底部,作为一个独立的大按钮展示。点击后同样通过showAlertDialog确认,确认后将UserInfo.isLogin置为 false,弹出 Toast 提示"退出成功",然后调用RouterModule.pop()返回上一页。

总结

SetUpPage是一个功能完整、设计成熟的设置页面实现。其技术亮点可以归纳为:

  1. 数据驱动:设置项列表通过SetupItem模型定义,增删改设置项只需修改数据数组,无需改动 UI 代码。
  2. 主题切换:利用ApplicationContext.setColorMode()系统 API 实现夜间模式,搭配DarkColorDialog提供友好的交互选择界面。
  3. 缓存管理:通过storageStatistics读取缓存大小,使用fileIo实现多目录递归删除,覆盖 EL1 加密区域。
  4. 安全机制:清除缓存和退出登录都通过 AlertDialog 二次确认,避免误操作。
  5. 状态持久化:主题选择通过PreferenceUtil持久化存储,应用重启后自动恢复用户偏好。

对于需要构建设置页面的 HarmonyOS 应用,SetUpPage提供了一份可参考的完整实现方案。

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

相关文章:

  • DS160PR410 EEPROM编程全解析:多设备配置与Hex文件生成实战
  • Django全栈开发旅游景点数据可视化系统实战
  • AI 写作趋势判断:从「生成式填充」到「结构性协作」的范式转移
  • 国产紫外可见分光光度计厂家有哪些|析谱/普析/棱光等国产厂家直达采购通道 - 品牌推荐大师
  • DP83849ID以太网PHY中断配置与寄存器详解:从原理到实战调试
  • 从0到1打造高沉浸虚拟展厅:20年数字基建老兵手把手拆解AI数字人驱动的Unity+WebGL+大模型融合架构
  • 高速ADC数据手册深度解读:从参数到系统设计的实战指南
  • Minpack集成指南:C/C++项目中非线性优化的经典引擎
  • 零成本搭建AI客服:火山引擎豆包API实战指南
  • HarmonyOS 应用开发《掌上英语》第55篇:LazyForEach vs ForEach 列表渲染性能优化
  • Opus 5在ARC-AGI-3基准测试创SOTA,突破AI抽象推理能力
  • Suiron:如何用机器学习打造自动驾驶RC车?完整入门指南
  • Spring Security权限控制:AccessDeniedException解析与处理
  • 5分钟掌握Backslash Powered Scanner配置:提升Web安全测试效率的终极技巧
  • Linux内核驱动面试高频“小”问题深度解析:从设备树到同步机制
  • 3步将PDF文档转化为智能知识图谱:llm-graph-builder让数据开口说话
  • 从Git版本控制到创作全脉络:技术策展如何实现艺术过程可视化
  • gh_mirrors/co/codespaces-project-template-js扩展指南:添加教育经历与技能展示模块全流程
  • AI-HF Patch:一站式解决AI少女游戏本地化与模组兼容性问题
  • Indigo游戏开发实战:5个简单步骤创建你的第一个2D游戏
  • 牵引逆变器可扩展设计:从模块化解耦到智能驱动的工程实践
  • UART异步通信原理与CP3SP33寄存器配置实战详解
  • 榆林市黄金回收就找鑫宸黄金奢品回收这七家 - 新芸鼎珠宝首饰
  • GyroFlow视频防抖终极指南:如何利用陀螺仪数据实现电影级稳定效果
  • 2026年更新怀化甲醛检测公司怎么选:只做检测不除醛的专业CMA资质实验室——居安环保CMA甲醛检测中心 - 绿呼吸检测中心
  • 终极RE引擎Mod框架:REFramework如何彻底改变游戏修改体验
  • Suiron训练指南:用Python和TensorFlow教RC车自主导航
  • 3步掌握PubMed批量下载:轻松实现文献自动化收集
  • HarmonyOS 应用开发《掌上英语》第56篇:@Trace 的代价——响应式系统的性能调优
  • GitHub加速终极方案:3分钟解决下载慢的完整指南