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

C++ vector深度剖析与模拟实现:探索模板的泛型应用

C++ vector深度剖析与模拟实现:探索模板的泛型应用

前引:在C++标准模板库STL中,vector是最常用的容器之一。它以动态数组的形式提供联系内存存储,支持随机访问和高效的尾部插入\删除操作。然而,其底层实现远非简单的数组封装,而是通过精妙的内存管理策略和数据结构设计,平衡了性能与灵活性。本文将深入探讨vector的底层实现原理,包括其核心数据结构、动态扩容机制、迭代器设计,以及实际应用中的注意事项~ 在上一个容器 string 的模拟实现中,我们发现 string 的模拟实现有些单调,它仅仅操作字符串,通过划分空间+类实现它的各种接口功能即可,难度还比较正常,思维逻辑正确代码不是问题;今天的 vector 作为新学的一个容器,它比 string 要复杂一些,因为它可以接纳各种类型,这就需要用到我们之前学的模板,不仅仅是写一个类这么简单~下面开始今天的vector实现,正文开始! 目录 vector的核心数据结构 模板框架搭建 构造初始化  析构函数 尾插数据  扩容 扩容+初始化 编辑 编辑 编辑

By Ne0inhk
【C++】第十九节—一文万字详解 | AVL树实现

【C++】第十九节—一文万字详解 | AVL树实现

好久不见,我是云边有个稻草人,偶尔中二博主与你分享C++领域专业知识^(* ̄(oo) ̄)^ 《C++》—本篇文章所属专栏—持续更新中—欢迎订阅~喔 目录 一、AVL的概念 二、AVL树的实现 2.1 AVL树的结构 2.2 AVL树的插入 【AVL树插入⼀个值的大概过程】 【平衡因⼦更新】 【插⼊结点及更新平衡因⼦的代码实现】  2.3 旋转 【旋转的原则】 【右单旋+两个坑+代码实现】 【左单旋+代码实现】 【左右双旋+代码实现】 【右左双旋+代码实现】 2.4 AVL树的查找 2.5 AVL树平衡检测 2.6 AVL树的删除

By Ne0inhk
DocxFactory: 一个C++操作word的开源库(不依赖office控件)

DocxFactory: 一个C++操作word的开源库(不依赖office控件)

目录 1.简介 2.环境搭建与依赖配置 3.模板设计核心技巧 4.常用场景示例 4.1.示例 1:简单文本替换(基础场景) 4.2.示例 2:动态生成表格(结构化数据场景) 4.3.示例 3:插入图片(含资源场景) 5.高级功能与技巧 6.常见问题与解决方案 7.与其他库的对比 8.总结 1.简介         DocxFactory 是一个专注于处理 Microsoft Word 文档(.docx 格式)的 C++ 库,主要用于动态创建、修改和生成 docx

By Ne0inhk
模板进阶:从非类型参数到分离编译,吃透 C++ 泛型编程的核心逻辑

模板进阶:从非类型参数到分离编译,吃透 C++ 泛型编程的核心逻辑

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 一. 非类型模板参数:让模板支持 “编译期常量配置” * 1.1 什么是非类型模板参数? * 1.2 必须遵守的 2 个关键规则 * 二. 模板特化:解决 “特殊类型” 的适配问题 * 2.1 解决 “通用模板失效” 的例子 * 2.2 类模板特化:比函数特化更常用 * 2.2.1 全特化:所有模板参数都确定 * 2.3.2 偏特化:对模板参数做 “条件限制”

By Ne0inhk