HarmonyOS6 半年磨一剑 - RcList 组件事件处理机制与应用示例

HarmonyOS6 半年磨一剑 - RcList 组件事件处理机制与应用示例

文章目录

前言

Hello 各位开发者们大家好, 我是若城,今天我们开始对Rchoui三方库新的组件开始讲解, 本期我们主要讲解的是 RcList 这个组件, 话不多说我们先看下效果图吧~~~

开源计划

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

rchoui 官网

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

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

一、触摸事件处理

1.1 触摸事件的用途

RcList 暴露了两个触摸事件,用于需要感知用户手势起止点的场景:

@EventonRcListTouchStart:(event: TouchEvent)=>void=()=>{}@EventonRcListTouchEnd:(event: TouchEvent)=>void=()=>{}

典型场景:

  • 触摸开始:暂停列表内的自动播放
  • 触摸结束:恢复自动播放或触发惯性动画

1.2 触摸事件的内部绑定

.onTouch((event: TouchEvent)=>{if(event.type === TouchType.Down){this.onRcListTouchStart(event)// 手指按下}elseif(event.type === TouchType.Up){this.onRcListTouchEnd(event)// 手指抬起}})

通过判断 event.type 将单一的 onTouch 事件拆分为更语义化的起止事件,简化了使用方的处理逻辑。


二、外部 Scroller 控制

2.1 Scroller 的注入与使用

通过 rcListScroller 参数注入外部 Scroller 实例,可以在组件外部控制列表滚动:

@Entry@ComponentV2 struct ScrollControlDemo {private scroller: Scroller =newScroller()build(){Column(){// 外部控制按钮Row({ space:12}){Button('回到顶部').onClick(()=>{this.scroller.scrollTo({ xOffset:0, yOffset:0})})Button('滚到底部').onClick(()=>{this.scroller.scrollEdge(Edge.Bottom)})}.margin({ bottom:12})// 注入 scrollerRcList({ rcListHeight:400, rcListScrollable:true, rcListScroller:this.scroller }){ForEach(Array.from<number,number>({ length:20},(_:number, i:number):number=> i),(index:number)=>{RcListItem({ rcListItemTitle:`列表项 ${index +1}`, rcListItemNote:`第 ${index +1} 条数据`})},(index:number):string=>`item-${index}`)}}.padding(16)}}

2.2 Scroller 常用 API

方法说明
scrollTo({ xOffset, yOffset })滚动到指定位置
scrollEdge(Edge.Top)滚动到顶部
scrollEdge(Edge.Bottom)滚动到底部
scrollBy(dx, dy)相对当前位置滚动
currentOffset()获取当前滚动偏移量

三、事件综合应用示例

以下是一个完整可运行的页面,综合演示所有交互机制:

import{ RcList, RcListItem }from'rchoui'@Entry@ComponentV2 struct RcListInteractionDemo {// 开关状态@Local switchA:boolean=true@Local switchB:boolean=false@Local switchC:boolean=true// 操作日志@Local logs:string[]=[]// 滚动控制器private scroller: Scroller =newScroller()// 添加日志privateaddLog(msg:string):void{const time =newDate().toLocaleTimeString()this.logs =[`[${time}] ${msg}`,...this.logs.slice(0,9)]}build(){Column({ space:0}){// 日志区域Column(){Text('操作日志').fontSize(14).fontWeight(FontWeight.Medium).margin({ bottom:8})ForEach(this.logs.slice(0,5),(log:string)=>{Text(log).fontSize(12).fontColor('#606266').width('100%')},(log:string):string=> log)if(this.logs.length ===0){Text('暂无操作记录').fontSize(12).fontColor('#c0c4cc')}}.width('100%').padding(12).backgroundColor('#fff').border({ width:{ bottom:1}, color:'#e4e7ed', style: BorderStyle.Solid })Scroll(){Column({ space:16}){// ===== 1. 点击交互 =====Text('点击交互').fontSize(16).fontWeight(FontWeight.Medium).margin({ top:16, bottom:4})RcList({ rcListBorder:true}){RcListItem({ rcListItemTitle:'普通点击项', rcListItemNote:'点击后记录日志', rcListItemClickable:true,onRcListItemClick:()=>{this.addLog('点击了「普通点击项」')}})RcListItem({ rcListItemTitle:'带右侧文字', rcListItemRightText:'详情', rcListItemClickable:true,onRcListItemClick:()=>{this.addLog('点击了「带右侧文字」,即将跳转')}})RcListItem({ rcListItemTitle:'无按压反馈', rcListItemNote:'不设置 clickable,无视觉反馈', rcListItemClickable:false,onRcListItemClick:()=>{this.addLog('点击了「无按压反馈」,事件仍然触发')}})}// ===== 2. 禁用状态 =====Text('禁用状态保护').fontSize(16).fontWeight(FontWeight.Medium).margin({ bottom:4})RcList({ rcListBorder:true}){RcListItem({ rcListItemTitle:'正常可点击', rcListItemNote:'点击会触发事件', rcListItemDisabled:false, rcListItemClickable:true,onRcListItemClick:()=>{this.addLog('「正常项」被点击')}})RcListItem({ rcListItemTitle:'已禁用(不可点击)', rcListItemNote:'即使设置了 clickable 也无效', rcListItemDisabled:true, rcListItemClickable:true,onRcListItemClick:()=>{this.addLog('这行永远不会出现在日志中')}})RcListItem({ rcListItemTitle:'已禁用的开关', rcListItemNote:'开关无法切换', rcListItemShowSwitch:true, rcListItemSwitchChecked:true, rcListItemDisabled:true, rcListItemShowArrow:false})}// ===== 3. 开关交互 =====Text('开关状态管理').fontSize(16).fontWeight(FontWeight.Medium).margin({ bottom:4})RcList({ rcListBorder:true}){RcListItem({ rcListItemTitle:'通知推送', rcListItemNote:this.switchA ?'已开启':'已关闭', rcListItemShowSwitch:true, rcListItemSwitchChecked:this.switchA, rcListItemShowArrow:false,onRcListItemSwitchChange:(checked:boolean)=>{this.switchA = checked this.addLog(`通知推送:${checked ?'开启':'关闭'}`)}})RcListItem({ rcListItemTitle:'自动更新', rcListItemNote:this.switchB ?'已开启':'已关闭', rcListItemShowSwitch:true, rcListItemSwitchChecked:this.switchB, rcListItemShowArrow:false,onRcListItemSwitchChange:(checked:boolean)=>{this.switchB = checked this.addLog(`自动更新:${checked ?'开启':'关闭'}`)}})RcListItem({ rcListItemTitle:'定位服务', rcListItemNote:this.switchC ?'已开启':'已关闭', rcListItemShowSwitch:true, rcListItemSwitchChecked:this.switchC, rcListItemShowArrow:false, rcListItemShowBorder:false,onRcListItemSwitchChange:(checked:boolean)=>{this.switchC = checked this.addLog(`定位服务:${checked ?'开启':'关闭'}`)}})}// ===== 4. 滚动事件 =====Text('滚动事件监听').fontSize(16).fontWeight(FontWeight.Medium).margin({ bottom:4})Row({ space:8}){Button('回到顶部').onClick(()=>{this.scroller.scrollEdge(Edge.Top)this.addLog('手动滚动到顶部')})Button('跳到底部').onClick(()=>{this.scroller.scrollEdge(Edge.Bottom)this.addLog('手动滚动到底部')})}RcList({ rcListHeight:240, rcListScrollable:true, rcListScroller:this.scroller, rcListScrollBarState: BarState.On, rcListBorder:true,onRcListScrollToLower:()=>{this.addLog('滚动到底部,可加载更多')},onRcListScrollToUpper:()=>{this.addLog('滚动到顶部,可下拉刷新')}}){ForEach(Array.from<number,number>({ length:15},(_:number, i:number):number=> i),(index:number)=>{RcListItem({ rcListItemTitle:`滚动列表项 ${index +1}`, rcListItemNote:`这是第 ${index +1} 条数据`, rcListItemRightText:`${index +1}`, rcListItemClickable:true,onRcListItemClick:()=>{this.addLog(`点击了第 ${index +1} 项`)}})},(index:number):string=>`scroll-item-${index}`)}Text('事件演示结束').fontSize(13).fontColor('#909399').textAlign(TextAlign.Center).margin({ top:8, bottom:30})}.width('100%').padding(16)}.layoutWeight(1).backgroundColor('#f5f5f5')}.width('100%').height('100%')}}

四、常见交互场景速查

4.1 场景对照表

场景关键参数说明
列表项可点击导航rcListItemClickable: true + onRcListItemClick标准导航项
开关设置项rcListItemShowSwitch: true + onRcListItemSwitchChange + rcListItemShowArrow: false设置页开关
禁用不可操作rcListItemDisabled: true权限不足/功能未解锁
无分割线末尾项rcListItemShowBorder: false最后一项去掉分割线
无箭头纯文字项rcListItemShowArrow: false展示信息,无跳转
加载更多onRcListScrollToLower + rcListHeight触底加载
下拉刷新触发点onRcListScrollToUpper回顶后刷新
外部控制滚动rcListScroller + Scroller 实例按钮控制回顶

4.2 禁用状态的注意事项

  1. 视觉透明度:禁用时整体 opacity: 0.6,不需要单独修改子元素样式
  2. 事件彻底阻断onRcListItemClickhandleRcListItemClick 中被拦截,不穿透
  3. 开关同步禁用rcListItemDisabled 会自动传递给内部 RcSwitch,无需额外设置
  4. 仅禁用视觉:如果只想改变外观而不阻断事件,可以不用 rcListItemDisabled,直接通过 opacity 修改

总结

RcList 的交互系统经过精心分层:点击反馈事件回调独立控制,禁用保护穿透视觉与行为双层,开关状态通过 @Local 内部状态实现解耦,滚动事件分三粒度按需监听,外部 Scroller 支持命令式控制。每个交互能力都可以独立使用,也可以自由组合,构成了一套完整、健壮的列表交互体系。

掌握这些交互机制,你可以实现设置页面、消息列表、联系人等高频应用场景,而无需关心底层的事件冒泡和状态管理细节。

如果这篇文章对你有帮助,欢迎点赞、收藏、关注,你的支持是我持续创作的动力!

Read more

我用Openclaw + Claude搭了一套自动写作系统,每天省3小时

我用Openclaw + Claude搭了一套自动写作系统,每天省3小时

这是我目前最重要的一套AI工作流。从信息获取到发布,几乎不用手动完成。 一、为什么我要搭建这套系统? 信息过载的困境 如果你也在持续关注AI,应该会有同样的感受: 信息太多了。 每天打开 X、公众号、GitHub、技术社区,都会冒出大量新内容。 AI模型更新、工具更新、Agent框架、自动化方案…… 想跟上这些信息,本身就已经是一项工作。 手动写作的低效循环 更别说: * 整理信息 * 找选题 * 写文章 * 配图 * 发布到各个平台 如果全部手动完成,写作就会变成一件非常消耗精力的事。 我一度也在这种状态里: 想持续输出,但写作本身占用了太多时间。 一个关键问题 后来我开始思考一个问题: 如果写作这件事可以被"系统化",会发生什么? 于是,我不再把AI当成写作工具。 而是开始搭一套完整的 AI写作工作流。 二、思路转变:从优化写作到优化流程 大多数人的AI写作方式 大多数人使用AI写作,是这样:

By Ne0inhk

核心期刊AIGC检测太严?SCI投稿降AI完整攻略

核心期刊AIGC检测太严?SCI投稿降AI完整攻略 TL;DR(太长不看):核心期刊和SCI对AI率要求极严,部分顶刊要求低于10%。完整攻略:投稿前用Turnitin检测→用AIGCleaner(英文首选)或嘎嘎降AI(中英通用)处理→人工检查术语和引用→用目标期刊的检测平台验证。AIGCleaner可将Turnitin AI率从95%降到5%以下,英文论文AI率建议控制在15%以下。 核心期刊和SCI对AI率要求有多严? 如果你正在准备投稿核心期刊或SCI,AI率问题必须提前重视。2026年各大期刊对AI生成内容的审查越来越严格,部分顶刊(比如Nature子刊、Science系列)明确要求AI率低于10%,普通SCI期刊一般要求低于20%。Turnitin、iThenticate这些检测系统也在不断升级算法,能够识别ChatGPT、Claude、DeepSeek等主流大模型的写作特征。我有个同事投Nature Communications,论文质量没问题,就因为AI率超标被编辑直接desk reject,几个月的心血付诸东流。所以投稿前一定要检测并处理AI率。 核心期刊

By Ne0inhk

GitHub 教育认证通过后如何领取 Copilot Pro

最近我通过了 GitHub 教育认证(Student Developer Pack),但是发现并没有立刻拿到 Copilot Pro。折腾了一番之后终于搞定了,这里记录一下过程,方便后面遇到同样问题的同学。 1. 教育认证通过 ≠ 立即开通 当你刚刚通过认证时,Student Pack 页面可能显示绿标,提示福利稍后开放,这时候需要等待几天到两周左右。 * 绿标:福利还在处理阶段(will be available soon)。 * 紫标:福利已经激活(benefits are now available)。 所以,如果你刚过认证但没看到 Copilot Pro,不用急,先等等。 2. 手动领取 Copilot Pro 即使福利已经激活,你也需要手动去领取: 👉 访问这个链接: https://github.com/github-copilot/

By Ne0inhk
彻底解决 Codex / Copilot 修改中文乱码【含自动化解决方案】

彻底解决 Codex / Copilot 修改中文乱码【含自动化解决方案】

引言 在使用 GitHub Copilot 或 OpenAI Codex 自动重构代码时,你是否遇到过这样的尴尬:AI 生成的代码逻辑完美,但原本注释里的中文却变成了 我爱中文 这样的乱码?有时候这种字符甚至会污染正确的代码,带来巨大的稳定性隐患。 一、 问题核心:被忽视的“终端中转” 乱码的根源不在于 AI 的大脑,也不在于编辑器的显示,而在于执行链路的编码不一致。 Copilot/Codex 在执行某些修改任务(如:重构整个文件或批量替换)时,往往会通过终端调用系统指令。由于 Windows 终端(PowerShell/CMD)默认使用 GBK 编码,它在处理 AI 传来的 UTF-8 字节时会发生“误读”,导致写入文件的内容从源头上就损坏了。

By Ne0inhk