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

📅 2026/7/29 15:01:59
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)})}}}参考创建列表