143.[HarmonyOS NEXT 实战案例十:List系列] 字母索引列表组件实战:打造高效联系人应用 基础篇 原创
[HarmonyOS NEXT 实战案例十:List系列] 字母索引列表组件实战:打造高效联系人应用 基础篇
项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star
效果演示
![143.[HarmonyOS NEXT 实战案例十:List系列] 字母索引列表组件实战:打造高效联系人应用 基础篇-鸿蒙开发者社区 143.[HarmonyOS NEXT 实战案例十:List系列] 字母索引列表组件实战:打造高效联系人应用 基础篇-鸿蒙开发者社区](https://dl-harmonyos.51cto.com/images/202506/d2f92d4413fffc64dbd3281caecbb8a583248f.png?x-oss-process=image/resize,w_373,h_597)
一、字母索引列表基础介绍
在HarmonyOS NEXT应用开发中,字母索引列表是一种常见的UI模式,特别适合展示按字母分类的数据,如联系人、城市列表等。通过结合ListItemGroup和AlphabetIndexer组件,我们可以创建一个既美观又高效的字母索引列表,提升用户查找体验。
1.1 字母索引列表的组成部分
| 组成部分 | 说明 | 
|---|---|
| List | 基础列表容器,用于展示所有内容 | 
| ListItemGroup | 分组组件,用于按字母分组显示列表项 | 
| AlphabetIndexer | 字母索引器,显示在列表侧边,用于快速导航到对应字母分组 | 
| Scroller | 滚动控制器,用于控制列表滚动到指定位置 | 
1.2 相关组件介绍
1.2.1 AlphabetIndexer组件
AlphabetIndexer是HarmonyOS NEXT提供的字母索引器组件,用于在列表旁边显示字母索引,支持用户通过点击或滑动快速定位到对应的列表位置。
| 主要属性 | 类型 | 说明 | 
|---|---|---|
| arrayValue | string[] | 索引器中显示的字符数组 | 
| selected | number | 当前选中项的索引 | 
| color | ResourceColor | 索引器的颜色 | 
| selectedColor | ResourceColor | 选中项的颜色 | 
| popupColor | ResourceColor | 弹出提示的颜色 | 
| selectedBackgroundColor | ResourceColor | 选中项的背景颜色 | 
| itemSize | number | 索引项的大小 | 
| font | Font | 索引项的字体样式 | 
| selectedFont | Font | 选中项的字体样式 | 
| popupFont | Font | 弹出提示的字体样式 | 
| usingPopup | boolean | 是否使用弹出提示 | 
| alignStyle | IndexerAlign | 索引器的对齐方式 | 
1.2.2 Scroller控制器
Scroller是HarmonyOS NEXT提供的滚动控制器,用于控制可滚动组件(如List)的滚动行为。
| 主要方法 | 说明 | 
|---|---|
| scrollTo | 滚动到指定位置 | 
| scrollToIndex | 滚动到指定索引的项 | 
| scrollEdge | 滚动到边缘 | 
| scrollPage | 滚动一页 | 
二、字母索引列表实战案例
2.1 需求分析
我们将实现一个按字母分组的联系人列表,包含以下功能:
- 联系人按首字母分组显示
 - 每个分组有明显的标题
 - 右侧显示字母索引器,支持快速导航
 - 点击字母索引时,列表自动滚动到对应分组
 - 列表滚动时,字母索引器同步更新选中状态
 
2.2 数据模型定义
首先,我们定义联系人和分组的数据模型:
interface ContactType {
    name: string,
    phone: string,
    avatar?: Resource
}
interface AlphabetIndexerType {
    key: string,
    contacts: ContactType[]
}
然后,准备按字母分组的联系人数据:
private contactGroups:AlphabetIndexerType[] = [
    {
        key: 'A',
        contacts: [
            { name: '艾伦', phone: '138-0000-0001', avatar: $r('app.media.big27') },
            { name: '安妮', phone: '138-0000-0002', avatar: $r('app.media.big26') },
            { name: '奥利弗', phone: '138-0000-0003', avatar: $r('app.media.big25') }
        ]
    },
    {
        key: 'B',
        contacts: [
            { name: '白露', phone: '138-0000-0004', avatar: $r('app.media.big24') },
            { name: '鲍勃', phone: '138-0000-0005', avatar: $r('app.media.big23') },
            { name: '贝蒂', phone: '138-0000-0006', avatar: $r('app.media.big22') }
        ]
    },
    // 其他字母分组...
]
2.3 获取索引字母数组
我们需要从联系人分组数据中提取所有的索引字母,用于AlphabetIndexer组件:
private get indexLetters(): string[] {
    return this.contactGroups.map(group => group.key)
}
2.4 分组头部实现
接下来,我们实现分组的头部,显示字母标题:
@Builder
GroupHeader(key: string) {
    Text(key)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .backgroundColor('#F1F3F5')
        .width('100%')
        .padding({ left: 16, top: 8, bottom: 8 })
}
2.5 页面结构设计
整个页面采用Stack布局,包含主要内容和字母索引器两部分:
build() {
    Stack({ alignContent: Alignment.TopEnd }) {
        // 主要内容
        Column() {
            // 标题栏
            Row() {
                // 标题栏内容
            }
            
            // 联系人列表
            List() {
                // 列表内容
            }
        }
        
        // 字母索引器
        AlphabetIndexer() {
            // 索引器配置
        }
    }
}
2.6 标题栏实现
标题栏包含标题文本和操作按钮:
Row() {
    Text('联系人')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
    Blank()
    Image($r('app.media.01'))
        .width(24)
        .height(24)
        .margin({ right: 16 })
    Image($r('app.media.02'))
        .width(24)
        .height(24)
        .margin({ right: 16 })
}
.width('100%')
.height(56)
.padding({ left: 16 })
.backgroundColor('#F1F3F5')
2.7 联系人列表实现
联系人列表使用List和ListItemGroup组件,按字母分组显示联系人:
private scroller: Scroller = new Scroller() // 滚动控制器
@State currentIndex: number = 0 // 当前索引
// 联系人列表
List({ scroller: this.scroller }) {
    ForEach(this.contactGroups, (group:AlphabetIndexerType, groupIndex) => {
        ListItemGroup({
            header: this.GroupHeader(group.key),
            space: 0
        }) {
            ForEach(group.contacts, (contact:ContactType) => {
                ListItem() {
                    Row() {
                        // 头像
                        Image(contact.avatar || $r('app.media.big1'))
                            .width(40)
                            .height(40)
                            .borderRadius(20)
                            .margin({ right: 16 })
                        // 联系人信息
                        Column() {
                            Text(contact.name)
                                .fontSize(16)
                                .fontWeight(FontWeight.Medium)
                            Text(contact.phone)
                                .fontSize(14)
                                .fontColor('#666666')
                                .margin({ top: 4 })
                        }
                        .alignItems(HorizontalAlign.Start)
                    }
                    .width('100%')
                    .padding({ left: 16, right: 16, top: 12, bottom: 12 })
                }
                .height(64)
            })
        }
    })
}
.width('100%')
.layoutWeight(1)
.onScrollIndex((firstIndex: number) => {
    // 更新当前索引
    this.currentIndex = firstIndex
})
.divider({ // 设置分割线
    strokeWidth: 1,
    color: '#E5E5E5',
    startMargin: 72,
    endMargin: 16
})
2.8 字母索引器实现
最后,我们实现字母索引器,并处理索引选择事件:
AlphabetIndexer({
    arrayValue: this.indexLetters,
    selected: this.currentIndex
})
    .itemSize(16) // 字母大小
    .font({ size: 14 }) // 字体大小
    .selectedFont({ size: 16, weight: FontWeight.Bold }) // 选中字体样式
    .popupFont({ size: 30, weight: FontWeight.Bold }) // 弹出字体样式
    .selectedBackgroundColor('#007DFF') // 选中背景色
    .popupColor('#CCCCCC') // 弹出颜色
    .usingPopup(true) // 使用弹出效果
    .alignStyle(IndexerAlign.Right) // 右侧对齐
    .margin({ right: 8 })
    .onSelect((index: number) => {
        // 滚动到对应索引位置
        this.currentIndex = index
        this.scroller.scrollToIndex(index)
    })
三、完整代码解析
@Component
export struct AlphabetIndexerList {
    private scroller: Scroller = new Scroller() // 滚动控制器
    @State currentIndex: number = 0 // 当前索引
    // 按字母分组的联系人数据
    private contactGroups:AlphabetIndexerType[] = [
        // 数据定义(同上)
    ]
    // 获取所有索引字母
    private get indexLetters(): string[] {
        return this.contactGroups.map(group => group.key)
    }
    // 构建分组头部
    @Builder
    GroupHeader(key: string) {
        // 头部实现(同上)
    }
    build() {
        Stack({ alignContent: Alignment.TopEnd }) {
            Column() {
                // 标题栏
                Row() {
                    // 标题栏实现(同上)
                }
                // 联系人列表
                List({ scroller: this.scroller }) {
                    // 列表实现(同上)
                }
            }
            .width('100%')
            .height('100%')
            // 字母索引器
            AlphabetIndexer({
                // 索引器实现(同上)
            })
        }
        .width('100%')
        .height('100%')
        .backgroundColor('#FFFFFF')
    }
}
3.1 代码结构分析
| 部分 | 说明 | 
|---|---|
| 数据模型 | 定义ContactType和AlphabetIndexerType接口,描述联系人和分组的数据结构 | 
| 数据准备 | 创建contactGroups数组,包含按字母分组的联系人数据 | 
| 索引字母 | 通过indexLetters计算属性获取所有索引字母 | 
| 构建器 | 定义GroupHeader构建器,用于创建分组的头部 | 
| 页面结构 | 使用Stack作为根容器,包含主要内容和字母索引器 | 
| 联系人列表 | 使用List和ListItemGroup创建分组列表,每个分组包含多个ListItem | 
| 字母索引器 | 使用AlphabetIndexer创建字母索引器,处理索引选择事件 | 
3.2 关键技术点分析
3.2.1 List与Scroller的结合使用
通过将Scroller实例传递给List组件,我们可以在外部控制列表的滚动行为:
private scroller: Scroller = new Scroller()
List({ scroller: this.scroller }) {
    // 列表内容
}
3.2.2 onScrollIndex事件处理
通过监听List的onScrollIndex事件,我们可以获取当前显示的第一个项的索引,用于更新字母索引器的选中状态:
.onScrollIndex((firstIndex: number) => {
    this.currentIndex = firstIndex
})
3.2.3 AlphabetIndexer与List的联动
通过AlphabetIndexer的onSelect事件和Scroller的scrollToIndex方法,我们实现了字母索引器与列表的联动:
.onSelect((index: number) => {
    this.currentIndex = index
    this.scroller.scrollToIndex(index)
})
3.2.4 Stack布局的使用
使用Stack布局可以将字母索引器叠加在主要内容上,并通过alignContent属性控制其位置:
Stack({ alignContent: Alignment.TopEnd }) {
    // 主要内容
    // 字母索引器
}
总结
在本篇教程中,我们学习了如何使用HarmonyOS NEXT的ListItemGroup和AlphabetIndexer组件创建一个字母索引列表。我们从数据模型定义、分组头部实现、页面结构设计到联系人列表和字母索引器实现,全面讲解了字母索引列表的实现过程。





















文章很不错!给我很大启发,用了你的demo哈