HarmonyOS6半年磨一剑 - RcIcon组件使用最佳实践与性能优化

HarmonyOS6半年磨一剑 - RcIcon组件使用最佳实践与性能优化

文章目录

前言

各位开发者,大家好!我是若城。

在鸿蒙应用开发过程中,我发现许多组件样式和工具方法具有高度的复用性,但每次新项目都需要重复编写,这极大地降低了开发效率。因此,我决定投入半年时间,打造一款专为鸿蒙生态设计的 UI 组件库 —— rchoui

项目简介

rchoui 是一个面向 HarmonyOS6 的企业级 UI 组件库,旨在提供开箱即用的高质量组件,让开发者告别"重复造轮子"。

核心特性

  • 丰富组件:涵盖基础组件、表单组件、弹窗组件、布局组件等
  • 设计规范:遵循统一的色彩体系和设计语言
  • 工具集成:内置常用工具方法,提升开发效率
  • 完善文档:每个模块都配有详细的设计思路和使用说明

开源计划

项目预计于 2026 年 7 月中旬正式开源,届时可通过三方库直接下载使用。在此期间,我会通过系列文章逐一介绍每个模块的设计思路与实现细节。

rchoui官网

目前暂定 rchoui 官网地址:http://rchoui.ruocheng.site/

需要注意的是 当前官网还在完善当中, 会在后续更新中逐步完善。届时可以为大家提供更加完善的说明文档

一、实战应用案例

1.1 底部导航栏

import{ RcIcon, IconName }from"rchoui"/** * Tab 项配置接口 */interfaceTabItem{/** Tab 名称 */ name:string/** 激活状态图标 */ icon:string/** 未激活状态图标(线型) */ iconOutline:string}@Entry@Component struct RcIconTab {@State activeIndex:number=0private tabItems: TabItem[]=[{ name:'首页', icon: IconName.HOME, iconOutline: IconName.HOME_OUTLINE},{ name:'发现', icon: IconName.COMPASS, iconOutline: IconName.COMPASS_OUTLINE},{ name:'消息', icon: IconName.MESSAGE_CIRCLE, iconOutline: IconName.MESSAGE_CIRCLE_OUTLINE},{ name:'我的', icon: IconName.PERSON, iconOutline: IconName.PERSON_OUTLINE}]build(){Row(){ForEach(this.tabItems,(item:TabItem, index)=>{Column({ space:4}){RcIcon({ name:this.activeIndex === index ? item.icon : item.iconOutline, iconSize:24, color:this.activeIndex === index ?'#1890ff':'#666666',onIconClick:()=>{this.activeIndex = index }})Text(item.name).fontSize(12).fontColor(this.activeIndex === index ?'#1890ff':'#666666')}.layoutWeight(1).padding(8)})}.width('100%').height(56).backgroundColor('#ffffff')}}

实现要点:

  • 使用风格切换表达激活状态
  • 颜色与风格同步变化
  • 统一的视觉反馈

1.2 工具栏按钮组

interfaceToolsItem{ id:string name:string}@Component struct ToolbarExample {@State selectedTool:string=''private tools:ToolsItem[]=[{ id:'edit', name: IconName.EDIT},{ id:'copy', name: IconName.COPY},{ id:'trash', name: IconName.TRASH},{ id:'share', name: IconName.SHARE}]build(){Row({ space:16}){ForEach(this.tools,(tool:ToolsItem)=>{RcIcon({ name: tool.name, iconSize:20, color:this.selectedTool === tool.id ?'#1890ff':'#666666',onIconClick:()=>{this.selectedTool = tool.id this.handleToolClick(tool.id)}})})}.padding(12).backgroundColor('#f5f5f5').borderRadius(8)}handleToolClick(toolId:string){console.log(`工具 ${toolId} 被点击`)}}

1.3 列表项装饰

interfaceListItem{ id:string title:string icon:string status:'success'|'warning'|'error'|'info'}@Component struct ListExample {private items: ListItem[]=[{ id:'1', title:'任务已完成', icon: IconName.CHECKMARK_CIRCLE, status:'success'},{ id:'2', title:'待处理事项', icon: IconName.ALERT_CIRCLE, status:'warning'},{ id:'3', title:'操作失败', icon: IconName.CLOSE_CIRCLE, status:'error'},{ id:'4', title:'通知消息', icon: IconName.INFO, status:'info'}]build(){List({ space:12}){ForEach(this.items,(item: ListItem)=>{ListItem(){Row({ space:12}){RcIcon({ name: item.icon, iconSize:20, color:this.getStatusColor(item.status)})Text(item.title).fontSize(16).layoutWeight(1)RcIcon({ name: IconName.CHEVRON_RIGHT, iconSize:16, color:'#cccccc'})}.width('100%').padding(16).backgroundColor('#ffffff').borderRadius(8)}})}.padding(16)}getStatusColor(status:string): ResourceColor {const colorMap ={'success':'#52c41a','warning':'#faad14','error':'#ff4d4f','info':'#1890ff'}return colorMap[status]||'#666666'}}

1.4 输入框前后缀

@Component struct InputExample {@State searchText:string=''@State showClear:boolean=falsebuild(){Row(){// 前缀符号RcIcon({ name: IconName.SEARCH, iconSize:18, color:'#999999'}).margin({ left:12})// 输入框TextInput({ placeholder:'搜索内容', text:this.searchText }).layoutWeight(1).backgroundColor(Color.Transparent).padding({ left:8, right:8}).onChange((value:string)=>{this.searchText = value this.showClear = value.length >0})// 后缀清除按钮if(this.showClear){RcIcon({ name: IconName.CLOSE_CIRCLE, iconSize:16, color:'#cccccc',onIconClick:()=>{this.searchText =''this.showClear =false}}).margin({ right:12})}}.width('100%').height(40).backgroundColor('#f5f5f5').borderRadius(20)}}

1.5 加载状态指示

@Component struct LoadingExample {@State isLoading:boolean=false@State rotationAngle:number=0build(){Column({ space:16}){// 旋转加载动画if(this.isLoading){RcIcon({ name: IconName.LOADER_OUTLINE, iconSize:32, color:'#1890ff', iconAnimation:{ duration:1000, curve: Curve.Linear, iterations:-1}}).rotate({ angle:this.rotationAngle }).onAppear(()=>{this.rotationAngle =360})Text('加载中...').fontSize(14).fontColor('#666666')}else{RcIcon({ name: IconName.CHECKMARK_CIRCLE, iconSize:32, color:'#52c41a'})Text('加载完成').fontSize(14).fontColor('#52c41a')}Button(this.isLoading ?'停止':'开始加载').onClick(()=>{this.isLoading =!this.isLoading if(!this.isLoading){this.rotationAngle =0}})}}}

1.6 空状态页面

@Component struct EmptyStateExample {@Prop emptyType:'noData'|'noNetwork'|'error'='noData'build(){Column({ space:20}){RcIcon({ name:this.getEmptyIcon(), iconSize:80, color:'#cccccc'})Text(this.getEmptyText()).fontSize(16).fontColor('#666666')if(this.emptyType ==='error'){Button('重新加载').onClick(()=>{// 重新加载逻辑})}}.width('100%').height('100%').justifyContent(FlexAlign.Center).backgroundColor('#f5f5f5')}getEmptyIcon():string{const iconMap ={'noData': IconName.FILE_OUTLINE,'noNetwork': IconName.WIFI_OFF_OUTLINE,'error': IconName.ALERT_TRIANGLE_OUTLINE}return iconMap[this.emptyType]}getEmptyText():string{const textMap ={'noData':'暂无数据','noNetwork':'网络连接失败','error':'加载失败'}return textMap[this.emptyType]}}

1.7 评分组件

@Component struct RatingExample {@State rating:number=0private maxRating:number=5build(){Row({ space:8}){ForEach(Array.from({ length:this.maxRating }),(_, index)=>{RcIcon({ name: index <this.rating ? IconName.STAR: IconName.STAR_OUTLINE, iconSize:24, color: index <this.rating ?'#faad14':'#d9d9d9',onIconClick:()=>{this.rating = index +1}})})}}}

1.8 标签页组件

@Component struct TabsExample {@State activeTab:number=0private tabs =[{ title:'推荐', icon: IconName.HOME},{ title:'关注', icon: IconName.HEART},{ title:'热门', icon: IconName.FLASH}]build(){Column(){// 标签页头部Row(){ForEach(this.tabs,(tab, index)=>{Column({ space:4}){RcIcon({ name: tab.icon, iconSize:20, color:this.activeTab === index ?'#1890ff':'#666666'})Text(tab.title).fontSize(14).fontColor(this.activeTab === index ?'#1890ff':'#666666')}.layoutWeight(1).padding(12).onClick(()=>{this.activeTab = index })})}.width('100%').backgroundColor('#ffffff')// 标签页内容区if(this.activeTab ===0){Text('推荐内容')}elseif(this.activeTab ===1){Text('关注内容')}else{Text('热门内容')}}}}

二、性能优化实践

2.1 避免过度渲染

❌ 不推荐:每次都重新创建

@Component struct BadExample {@State count:number=0build(){Column(){// 问题:每次count变化,所有符号都重新渲染RcIcon({ name: IconName.HOME, iconSize:20})RcIcon({ name: IconName.SEARCH, iconSize:20})RcIcon({ name: IconName.PERSON, iconSize:20})Text(this.count.toString())}}}

✅ 推荐:使用@Reusable优化

@Reusable@Component struct IconItem {@Param iconName:string=''build(){RcIcon({ name:this.iconName, iconSize:20})}}@Component struct GoodExample {@State count:number=0build(){Column(){IconItem({ iconName: IconName.HOME})IconItem({ iconName: IconName.SEARCH})IconItem({ iconName: IconName.PERSON})Text(this.count.toString())}}}

2.2 列表性能优化

使用LazyForEach优化大列表

classBasicDataSourceimplementsIDataSource{private listeners: DataChangeListener[]=[]private data:string[]=[]getData(index:number):string{returnthis.data[index]}totalCount():number{returnthis.data.length }registerDataChangeListener(listener: DataChangeListener):void{this.listeners.push(listener)}unregisterDataChangeListener(listener: DataChangeListener):void{const index =this.listeners.indexOf(listener)if(index >=0){this.listeners.splice(index,1)}}}@Component struct OptimizedListExample {private dataSource: BasicDataSource =newBasicDataSource()build(){List(){LazyForEach(this.dataSource,(item:string, index:number)=>{ListItem(){Row({ space:12}){RcIcon({ name: IconName.FILE, iconSize:20, color:'#666666'})Text(item).fontSize(16)}.padding(16)}},(item:string)=> item)}}}

2.3 动画性能优化

控制动画数量

@Component struct AnimationExample {@State visibleIcons:number=5private maxIcons:number=100build(){Column(){// 只为可见的符号添加动画ForEach(Array.from({ length: Math.min(this.visibleIcons,this.maxIcons)}),(_, index)=>{RcIcon({ name: IconName.STAR, iconSize:20, iconAnimation:{ duration:300, delay: index *50// 错开动画时间}})})}}}

使用动画开关

@StorageLink('enableAnimations') enableAnimations:boolean=trueRcIcon({ name: IconName.LOADER_OUTLINE, iconSize:24, iconAnimation:this.enableAnimations ?{ duration:1000, iterations:-1}:undefined})

2.4 资源加载优化

延迟加载非关键符号

@Component struct LazyLoadExample {@State showDetails:boolean=falsebuild(){Column({ space:12}){// 始终显示的关键符号RcIcon({ name: IconName.HOME, iconSize:24})Button('显示详情').onClick(()=>{this.showDetails =true})// 延迟加载的符号if(this.showDetails){Row({ space:8}){RcIcon({ name: IconName.EDIT, iconSize:20})RcIcon({ name: IconName.TRASH, iconSize:20})RcIcon({ name: IconName.SHARE, iconSize:20})}}}}}

2.5 内存优化

及时清理资源

@Component struct MemoryOptimizedExample {@State rotationAngle:number=0private animationTimer?:numberaboutToAppear(){this.startAnimation()}aboutToDisappear(){// 清理定时器if(this.animationTimer){clearInterval(this.animationTimer)this.animationTimer =undefined}}startAnimation(){this.animationTimer =setInterval(()=>{this.rotationAngle =(this.rotationAngle +10)%360},50)}build(){RcIcon({ name: IconName.SYNC, iconSize:30}).rotate({ angle:this.rotationAngle })}}

三、可访问性支持

3.1 语义化标签

RcIcon({ name: IconName.CLOSE}).accessibilityText('关闭按钮').accessibilityDescription('点击关闭当前窗口')

3.2 焦点管理

@State isFocused:boolean=falseRcIcon({ name: IconName.BUTTON, color:this.isFocused ?'#0066cc':'#0080ff'}).focusable(true).onFocus(()=>{this.isFocused =true}).onBlur(()=>{this.isFocused =false})

3.3 触摸区域扩展

// 符号本身较小时,扩大触摸区域Stack(){RcIcon({ name: IconName.SMALL, iconSize:16})}.width(44)// 最小44x44的触摸区域.height(44).onClick(()=>{// 点击处理})

四、跨平台适配

4.1 屏幕密度适配

@State screenDensity:number= display.getDefaultDisplaySync().densityDPI /160RcIcon({ name: IconName.LOGO, iconSize:24*this.screenDensity // 根据密度缩放})

4.2 暗黑模式适配

@StorageLink('colorMode') colorMode: ThemeColorMode = ThemeColorMode.LIGHTRcIcon({ name: IconName.THEME, color:this.colorMode === ThemeColorMode.DARK?'#ffffff':'#000000'})

4.3 多语言支持

// 对于方向性符号,考虑RTL布局@StorageLink('isRTL') isRTL:boolean=falseRcIcon({ name:this.isRTL ? IconName.ARROW_LEFT: IconName.ARROW_RIGHT, iconSize:20})

五、调试技巧

5.1 符号渲染检查

// 开发模式下显示符号名称@State showDebugInfo:boolean= BuildProfile.DEBUGRcIcon({ name: IconName.TEST}).border({ width:this.showDebugInfo ?1:0, color:'#ff0000'})if(this.showDebugInfo){Text('IconName.TEST').fontSize(10).fontColor('#ff0000')}

5.2 性能监控

@Component struct PerformanceMonitor {@State renderCount:number=0aboutToAppear(){this.renderCount++console.log(`组件渲染次数: ${this.renderCount}`)}build(){RcIcon({ name: IconName.MONITOR})}}

六、常见错误与解决方案

6.1 符号不显示

问题: 符号名称拼写错误

// ❌ 错误:拼写错误RcIcon({ name:'icon-houi_hom'})// ✅ 正确:使用常量避免拼写错误RcIcon({ name: IconName.HOME})

问题: 字体未加载

// 确保字体文件存在于rawfile目录// 路径:entry/src/main/resources/rawfile/rc_font.woff

6.2 颜色不生效

问题: 图片格式不支持颜色填充

// ❌ PNG图片不支持fillColorRcIcon({ name:'https://example.com/logo.png', color:'#ff0000'// 无效})// ✅ 使用SVG或字体符号RcIcon({ name: IconName.LOGO, color:'#ff0000'// 有效})

6.3 动画卡顿

问题: 同时运行过多动画

// ❌ 100个符号同时动画ForEach(Array.from({ length:100}),()=>{RcIcon({ name: IconName.STAR, iconAnimation:{...}})})// ✅ 限制同时动画数量ForEach(Array.from({ length:100}),(_, index)=>{RcIcon({ name: IconName.STAR, iconAnimation: index <10?{...}:undefined})})

6.4 内存泄漏

问题: 动画未清理

// ❌ 忘记清理定时器privatestartRotation(){setInterval(()=>{this.angle +=10},50)}// ✅ 在生命周期中清理private timer?:numberaboutToAppear(){this.timer =setInterval(()=>{this.angle +=10},50)}aboutToDisappear(){if(this.timer){clearInterval(this.timer)}}

七、版本兼容性

7.1 API版本检查

import{ systemCapability }from'@ohos.ability.ability'if(systemCapability.querySystemCapability('SystemCapability.ArkUI.ArkUI.Full')){// 使用新APIRcIcon({ name: IconName.NEW_FEATURE, iconAnimation:{...}})}else{// 降级处理RcIcon({ name: IconName.NEW_FEATURE})}

7.2 功能降级

// 检测是否支持动画@State supportsAnimation:boolean=trueRcIcon({ name: IconName.LOADER, iconAnimation:this.supportsAnimation ?{ duration:1000, iterations:-1}:undefined})

八、总结

8.1 核心要点

  1. 类型安全优先:使用IconName常量避免错误
  2. 性能意识:合理控制渲染和动画
  3. 用户体验:提供清晰的视觉反馈
  4. 可访问性:支持无障碍功能
  5. 可维护性:编写清晰、可测试的代码

8.2 应用价值

RcIcon作为UI库的基础组件,在实际项目中:

  • 减少50%以上的符号集成时间
  • 提供统一的视觉语言
  • 保证跨平台一致性
  • 支持主题定制和扩展
  • 性能优化开箱即用

Read more

python八股文汇总(持续更新版)

python装饰器 一、装饰器是什么? 装饰器是Python中一种"化妆师",它能在不修改原函数代码的前提下,给函数动态添加新功能。 * 本质:一个接收函数作为参数,并返回新函数的工具。 * 作用:像给手机贴膜,既保护屏幕(原函数),又新增防摔功能(装饰逻辑)。 二、核心原理 1. 函数是"对象":Python中函数可以像变量一样传递,这是装饰器的基础。 2. 闭包机制:装饰器通过嵌套函数(闭包)保留原函数,并包裹新功能。 工作流程: 1. 你调用被装饰的函数(如hello())。 2. Python实际执行的是装饰器加工后的新函数。 3. 新函数先执行装饰器添加的逻辑(如权限检查),再执行原函数。 三、常见用途 场景 作用 生活类比 权限验证 检查用户是否登录再执行函数

By Ne0inhk
【免费领源码】96007物流车辆预约平台 计算机毕业设计项目推荐上万套实战教程JAVA,node.js,C++、python、大屏数据可视化

【免费领源码】96007物流车辆预约平台 计算机毕业设计项目推荐上万套实战教程JAVA,node.js,C++、python、大屏数据可视化

目 录 物流车辆预约平台 摘  要 第1章 绪论 1.1背景及意义 1.2 研究现状 1.3  论文组成结构 第2章 相关技术 2.1 B/S体系工作原理 2.2 Django框架介绍 2.3 MySQL数据库 第3章 系统分析 3.1 系统可行性分析 3.1.1技术可行性 3.1.2经济可行性 3.1.3操作可行性 3.2 功能需求分析 3.3 非功能性分析 3.4系统流程分析 3.

By Ne0inhk

ezdxf库终极指南:Python CAD自动化从入门到精通

ezdxf库终极指南:Python CAD自动化从入门到精通 【免费下载链接】ezdxfPython interface to DXF 项目地址: https://gitcode.com/gh_mirrors/ez/ezdxf 想要用Python操控CAD图纸却不知从何入手?ezdxf库为你打开了通往CAD自动化世界的大门。这个纯Python实现的DXF文件处理工具,让你无需安装任何CAD软件就能轻松读写、编辑和生成图纸文件。无论你是机械工程师、建筑设计师,还是数据可视化开发者,掌握ezdxf都将让你的工作效率倍增。 快速入门:5分钟上手ezdxf 安装与环境配置 安装ezdxf库只需一行命令,简单到让人难以置信: pip install ezdxf 验证安装是否成功: import ezdxf print(f"ezdxf版本: {ezdxf.__version__}") 你的第一个DXF文件 让我们从一个简单的例子开始,感受ezdxf的强大之处: import ezdxf # 创建新图纸 -

By Ne0inhk

Python从0到100完整学习指南(必看导航)

Python 从 0 到 100 完整学习路线(2025–2026 实用版) 这是一条目前在中文社区被验证最多次、性价比最高、就业/副业/考研/转行都适用的 Python 学习路径。 分为 8 个大阶段,每个阶段给出: * 核心目标 * 推荐学习时长(每天 2–4 小时估算) * 最值得学的资源(2025–2026 仍活跃且评价最高的) * 必须掌握的技能清单 * 阶段性小目标 / 实战项目建议 阶段划分总览表 阶段名称目标人群建议时长累计总时长核心关键词0准备期完全零基础3–7 天1 周环境、IDE、学习心态1Python 基础语法零基础 → 能写小工具3–6 周1–2 个月变量、循环、函数、类2Pythonic

By Ne0inhk