HarmonyOS掌上记账APP开发实践第98篇:如何按字母分组展示联系人列表

发布时间:2026/9/13 17:32:34

HarmonyOS掌上记账APP开发实践第98篇:如何按字母分组展示联系人列表 如何按字母分组展示联系人场景说明在通讯录中需要将联系人按照姓氏的首字母进行分组排列从而更方便联系人的查找联系人列表右侧的字母导航可以随列表的滑动而定位到对应字母处同时也可以通过字母导航控制列表跳到指定联系人分组。本例即为大家介绍如何实现上述场景。效果呈现本demo示例最终效果如下实现思路本例涉及的四个关键特性及其实现方案如下联系人按字母分组展示通过List组件显示联系人列表通过ListItemGroup组件实现联系人分组。联系人右侧呈现字母导航使用AlphabetIndexer组件实现字母导航同时通过Stack组件使字母导航浮在联系人列表右侧。滑动联系人列表右侧字母导航随之变动通过List组件的onScrollIndex事件获取到联系人列表的滑动位置并将该位置索引传递给字母导航的selected属性作为字母导航的被选中项。通过右侧字母导航控制联系人列表滑动到指定分组通过字母导航的onSelected事件获取选中字母的索引并将该索引传递给联系人列表的控制器控制列表滑动到指定分组。开发步骤针对上述关键特性具体实现步骤如下1、通过Stack、List、ListItemGroup、AlphabetIndexer等关键组件将UI框架搭建起来。先构建列表数据其中Contact为联系人数据类。contactGroups:object[][...{title:D,contacts:[newContact(Donna,$r(app.media.contact6)),newContact(朵朵,$r(app.media.contact1)),],},...{title:K,contacts:[newContact(孔孔,$r(app.media.contact2)),newContact(康康,$r(app.media.contact3)),],},{title:L,contacts:[newContact(Lisa,$r(app.media.contact4)),newContact(玲玲,$r(app.media.contact5)),],},{title:N,contacts:[newContact(牛牛,$r(app.media.contact6)),newContact(Natasha,$r(app.media.contact1)),],},...]有了列表数据后我们来构建UI框架关键代码如下EntryComponentstruct ContactList{...// 自定义组件groupHeader作为ListItemGroup的头部组件即A、B、C等字母列表项BuildergroupHeader(titleLetter:string){Text(titleLetter).fontSize(20).backgroundColor(#fff1f3f5).width(100%).padding(5)}// 创建字母列表作为字母导航的内容privatealphabets:string[][A,B,D,G,K,L,N,X];build(){Stack({alignContent:Alignment.End}){List(){// 循环渲染列表内容ForEach(this.contactGroups,contactGroup{// 采用ListItemGroup对联系人进行分组将groupHeader作为ListItemGroup的头部组件ListItemGroup({header:this.groupHeader(contactGroup.title)}){ForEach(contactGroup.contacts,contact{ListItem(){Column(){Row(){Image(contact.icon)...Text(contact.name)}...Divider().color(#fff1f3f5)}...}})}})}...// 使用AlphabetIndexer组件实现右侧字母导航AlphabetIndexer({arrayValue:this.alphabets,selected:0})...}}}完成上述代码我们的框架就搭建起来了如图2、接下来为UI框架添加逻辑控制。首先通过List的onScrollIndex事件获取到列表滑动位置的索引并将索引同步给右侧字母表的selected属性从而在滑动联系人时使右侧字母导航随之变动关键代码如下...// 创建动态变量用于指定字母导航的选择项StateselectedIndex:number0;...build(){Stack({alignContent:Alignment.End}){List({scroller:this.listScroller}){ForEach(this.contactGroups,contactGroup{ListItemGroup({header:this.groupHeader(contactGroup.title)}){ForEach(contactGroup.contacts,contact{ListItem(){...}})}})}...// 获取联系人列表滑动位置的索引并将索引通过selectedIndex同步给右侧字母导航.onScrollIndex((firstIndex:number){this.selectedIndexfirstIndex})AlphabetIndexer({arrayValue:this.alphabets,selected:0})...// 指定字母导航的选择项为selectedIndex完成跟联系人列表的同步.selected(this.selectedIndex)...}}至此当我们滑动联系人列表时就可以让右侧字母导航随之变动了。效果如下3、最后我们通过AlphabetIndexer组件的onSelect事件获取到字母导航选择项的索引然后通过List组件的scroller控制器控制联系人列表滑动到相同的索引处从而实现通过右侧字母导航控制联系人列表滑动到指定分组。关键代码如下...StateselectedIndex:number0;// 创建List组件的scroller控制器listScroller用于控制联系人列表的滑动位置privatelistScroller:ScrollernewScroller()...build(){Stack({alignContent:Alignment.End}){// 将scroller控制器绑定到List组件List({scroller:this.listScroller}){ForEach(this.contactGroups,contactGroup{ListItemGroup({header:this.groupHeader(contactGroup.title)}){ForEach(contactGroup.contacts,contact{ListItem(){...}})}})}...AlphabetIndexer({arrayValue:this.alphabets,selected:0})...// 获取字母导航中选中字母的索引值并通过listScroller控制列表滑动到对应索引位置.onSelect((index:number){this.listScroller.scrollToIndex(index)})...}}至此当我们在右侧字母导航选择某个字母时就可以控制联系人列表跳转到指定分组了效果如下完整代码通过上述步骤我们已经完成了整个示例的开发现提供本示例的完整代码供大家参考联系人数据类代码// ListModel.etsexportdefaultclassContact{name:string;icon:Resource;constructor(name:string,icon:Resource){this.namenamethis.iconicon}}案例主代码// Contact.etsimportContactfrom../model/ListModelEntryComponentstruct ContactList{// 联系人列表数据contactGroups:object[][{title:A,contacts:[newContact(艾薇而,$r(app.media.contact1)),newContact(安琪,$r(app.media.contact2)),newContact(Angela,$r(app.media.contact3)),],},{title:B,contacts:[newContact(Bobe,$r(app.media.contact4)),newContact(勃勃,$r(app.media.contact5)),],},{title:D,contacts:[newContact(Donna,$r(app.media.contact6)),newContact(朵朵,$r(app.media.contact1)),],},{title:G,contacts:[newContact(Gavin,$r(app.media.contact4)),newContact(果味,$r(app.media.contact1)),],},{title:K,contacts:[newContact(孔孔,$r(app.media.contact2)),newContact(康康,$r(app.media.contact3)),],},{title:L,contacts:[newContact(Lisa,$r(app.media.contact4)),newContact(玲玲,$r(app.media.contact5)),],},{title:N,contacts:[newContact(牛牛,$r(app.media.contact6)),newContact(Natasha,$r(app.media.contact1)),],},{title:X,contacts:[newContact(小可爱,$r(app.media.contact2)),newContact(徐总是,$r(app.media.contact3)),newContact(璇璇,$r(app.media.contact3)),newContact(欣欣,$r(app.media.contact3)),],},]// 自定义组件groupHeader作为ListItemGroup的头部组件即A、B、C等字母列表项BuildergroupHeader(titleLetter:string){Text(titleLetter).fontSize(20).backgroundColor(#fff1f3f5).width(100%).padding(5)}// 创建字母列表作为字母导航的内容privatealphabets:string[][A,B,D,G,K,L,N,X];// 创建动态变量用于指定字母导航的选择项StateselectedIndex:number0;// 创建List组件的scroller控制器listScroller用于控制联系人列表的滑动位置privatelistScroller:ScrollernewScroller()build(){Stack({alignContent:Alignment.End}){// 将scroller控制器绑定到List组件List({scroller:this.listScroller}){// 循环渲染列表内容ForEach(this.contactGroups,contactGroup{// 采用ListItemGroup对联系人进行分组将groupHeader作为ListItemGroup的头部组件ListItemGroup({header:this.groupHeader(contactGroup.title)}){ForEach(contactGroup.contacts,contact{ListItem(){Column(){Row(){Image(contact.icon).width(35).height(35).margin(10)Text(contact.name)}.width(100%)Divider().color(#fff1f3f5)}.justifyContent(FlexAlign.Start)}})}})}.width(100%).height(100%).scrollBar(BarState.Auto)// 获取联系人列表滑动位置的索引并将索引通过selectedIndex同步给右侧字母导航.onScrollIndex((firstIndex:number){this.selectedIndexfirstIndex})// 使用AlphabetIndexer组件实现右侧字母导航AlphabetIndexer({arrayValue:this.alphabets,selected:0}).margin({right:10}).itemSize(25).font({size:15})// 指定字母导航的选择项为selectedIndex完成跟联系人列表的同步.selected(this.selectedIndex)// 获取选中字母的索引值通过listScroller控制列表滑动到对应索引位置.onSelect((index:number){this.listScroller.scrollToIndex(index)})}}}参考创建列表
延伸阅读

更多相关文章

2026/9/12 1:30:26

MAXScript自动化:3D艺术家的编程进阶指南

1. 项目概述:当艺术思维遇上编程逻辑那天在Autodesk 3ds Max里重复第37次调整模型UV时,我突然意识到——艺术家和开发者之间只隔着一行MAXScript代码的距离。这个发现彻底改变了我的工作方式:从每天手动调整数百个模型参数,到用脚…

2026/9/11 19:56:18

22 对称量化与非对称量化——INT8的两种尺度计算方式

对称量化与非对称量化——INT8的两种尺度计算方式 一句话总结:对称量化让 0 永远映射到 0,反量化简单;非对称量化利用全部 256 个值,但需要额外的 zero_point 偏移。 前言 在 INT8 量化中,如何将 FP32 的浮点数映射到…

2026/9/12 8:36:32

COMSOL多物理场耦合在水力压裂模拟中的应用与实践

1. 项目概述:COMSOL在水力压裂模拟中的独特价值 水力压裂技术作为非常规油气资源开发的核心手段,其模拟过程涉及复杂的多物理场耦合问题。传统单一物理场仿真工具往往难以准确刻画裂缝扩展与流体渗流的相互作用,这正是COMSOL Multiphysics的突…

2026/9/13 17:27:55

Qt和SQL开发教室管理系统:项目实现与部署指南

简介:基于QT与SQL数据库开发的教室管理系统源码包,面向计算机相关专业学生及有Qt开发基础的学习者,适合作为课程大作业、毕业设计或数据库课程综合项目的参考样板。系统围绕教室资源管理设计,涵盖教室信息维护、空教室查询、预约与…

2026/9/13 17:27:55

油藏数值模拟中的IMPES方法原理与MATLAB实现

1. 油藏数值模拟中的两相流动问题本质 在地下油气藏开发过程中,流体流动行为直接影响着采收率预测和开发方案制定。两相流动(通常指油水两相或油气两相)的模拟计算,需要同时考虑质量守恒方程、动量守恒方程以及相间相互作用力。这…

2026/9/13 17:22:55

卡尔曼滤波动态价差追踪:gs-quant 十分钟回测指南

卡尔曼滤波动态价差追踪:gs-quant 十分钟回测指南 【免费下载链接】gs-quant Python toolkit for quantitative finance 项目地址: https://gitcode.com/GitHub_Trending/gs/gs-quant 2024年5月13日,豆粕-菜粕价差一周内从 287 元/吨跳到 412 元&…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/13 11:18:28

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码