发布时间:2026/7/29 15:02:13
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/7/29 15:02:13

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

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

2026/7/29 15:02:13

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

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

2026/7/29 15:02:13

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

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

2026/7/29 18:18:18

网盘直链下载助手:告别客户端限制,三步获取真实下载链接

网盘直链下载助手:告别客户端限制,三步获取真实下载链接 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移…

2026/7/29 18:18:18

如何在macOS上获得专业级视频播放体验:IINA完全指南

如何在macOS上获得专业级视频播放体验:IINA完全指南 【免费下载链接】iina The modern video player for macOS. 项目地址: https://gitcode.com/gh_mirrors/iin/iina 还在为macOS上的视频播放体验不够完美而烦恼吗?今天我要向你介绍一款专为macO…

2026/7/29 18:13:18

卓健易控信创LIS系统(信创实验室信息系统)

LIS系统(实验室信息系统)作为医疗、科研等领域的关键信息化工具,其信创化(信息技术应用创新国产化)不仅是技术升级的必然趋势,更是国家信息安全、数据主权和产业自主可控的重要保障。以下从国家政策背景及重…

2026/7/28 13:41:25

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

一、背景与测试方案 在实际项目交付中,PDF文件合并与版权保护水印的叠加是一个高频但容易被低估的技术需求。典型的处理链路涉及:多源PDF的文件流合并、页面级水印渲染(含透明度混合与图层叠加)、输出文件体积控制。看似简单的操作…

2026/7/29 0:02:56

商标注册找代理还是自己办?算清这笔“时间账”和“风险账

商标注册,找代理还是自己办?帮你算清这笔“时间账”和“风险账”“商标注册,找代理还是自己办?”这是深圳每个创业者都会遇到的灵魂拷问。有人说找代理是花冤枉钱,有人说自己办风险太高。到底哪种更划算?本…

2026/7/29 0:02:56

免费开源RPA工具OpenRPA:企业级自动化流程的终极解决方案

免费开源RPA工具OpenRPA:企业级自动化流程的终极解决方案 【免费下载链接】openrpa Free Open Source Enterprise Grade RPA 项目地址: https://gitcode.com/gh_mirrors/op/openrpa 你是否厌倦了每天重复枯燥的数据录入和报表整理工作?是否希望有…

2026/7/29 0:02:56

KMS智能激活工具:一站式解决Windows和Office激活难题

KMS智能激活工具:一站式解决Windows和Office激活难题 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为系统弹出激活提示而烦恼吗?KMS智能激活工具能够帮你彻底告别W…

2026/7/29 13:12:43

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…