在鸿蒙HarmonyOS 5中实现微信式通讯录列表与指示导航栏交互
·
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似微信通讯录的列表与字母导航栏交互效果。
1. 项目结构与基础配置
首先确保你的DevEco Studio项目已配置HarmonyOS 5 SDK,并在config.json中添加必要的权限:
"abilities": [
{
"name": "MainAbility",
"type": "page",
"launchType": "standard"
}
],
"reqPermissions": [
{
"name": "ohos.permission.READ_CONTACTS"
}
]
2. 数据模型定义
定义联系人数据结构:
// Contact.ets
export class Contact {
id: string = "";
name: string = "";
avatar: string = "";
phone: string = "";
// 获取首字母大写
get firstLetter(): string {
return this.name.charAt(0).toUpperCase();
}
}
3. 实现通讯录列表与导航栏
主页面实现
// Index.ets
import { Contact } from './Contact';
import promptAction from '@ohos.promptAction';
@Entry
@Component
struct Index {
@State contacts: Contact[] = []; // 联系人列表
@State letters: string[] = []; // 字母导航列表
@State currentLetter: string = ""; // 当前选中的字母
@State showLetterTip: boolean = false; // 是否显示字母提示
// 模拟加载联系人数据
onPageShow() {
this.loadContacts();
}
loadContacts() {
// 实际项目中应从联系人服务获取数据
const mockContacts = [
{id: "1", name: "张三", avatar: "", phone: "13800138000"},
{id: "2", name: "李四", avatar: "", phone: "13800138001"},
// 更多联系人...
];
this.contacts = mockContacts.sort((a, b) => a.name.localeCompare(b.name));
this.generateLetters();
}
// 生成字母导航列表
generateLetters() {
const letterSet = new Set<string>();
this.contacts.forEach(contact => {
letterSet.add(contact.firstLetter);
});
this.letters = Array.from(letterSet).sort();
}
// 滚动到指定字母位置
scrollToLetter(letter: string) {
const index = this.contacts.findIndex(item => item.firstLetter === letter);
if (index >= 0) {
// 这里需要获取List组件的controller来实现滚动
// 实际实现见下方完整代码
this.currentLetter = letter;
this.showLetterTip = true;
// 1秒后隐藏字母提示
setTimeout(() => {
this.showLetterTip = false;
}, 1000);
}
}
build() {
Column() {
// 联系人列表
List({ space: 0 }) {
ForEach(this.contacts, (contact: Contact) => {
ListItem() {
ContactItem({ contact: contact })
}
}, (contact: Contact) => contact.id)
}
.width('100%')
.layoutWeight(1)
// 字母导航栏
Column() {
ForEach(this.letters, (letter: string) => {
Text(letter)
.fontSize(14)
.fontColor(this.currentLetter === letter ? '#07C160' : '#666666')
.margin({ top: 2, bottom: 2 })
.onClick(() => {
this.scrollToLetter(letter);
})
}, (letter: string) => letter)
}
.width(30)
.margin({ right: 10 })
.alignItems(HorizontalAlign.End)
// 字母提示框
if (this.showLetterTip) {
Text(this.currentLetter)
.fontSize(32)
.fontColor(Color.White)
.backgroundColor('#888888')
.opacity(0.8)
.padding(20)
.borderRadius(10)
.position({ x: '50%', y: '50%' })
.align(Alignment.Center)
}
}
.width('100%')
.height('100%')
}
}
// 联系人列表项组件
@Component
struct ContactItem {
@Prop contact: Contact;
build() {
Row() {
Image(this.contact.avatar || 'resources/contact_default.png')
.width(40)
.height(40)
.borderRadius(20)
.margin({ right: 10 })
Column() {
Text(this.contact.name)
.fontSize(16)
Text(this.contact.phone)
.fontSize(12)
.fontColor('#999999')
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
}
.width('100%')
.padding(10)
.borderRadius(5)
}
}
4. 实现列表分组与字母标题
增强列表实现,添加分组标题:
// 修改Index组件的build方法中的List部分
List({ space: 0 }) {
let lastLetter = "";
ForEach(this.contacts, (contact: Contact) => {
// 如果首字母变化,添加字母标题
if (contact.firstLetter !== lastLetter) {
ListItem() {
Text(contact.firstLetter)
.fontSize(18)
.fontColor('#999999')
.backgroundColor('#F5F5F5')
.width('100%')
.padding(10)
}
.sticky(Sticky.Normal)
lastLetter = contact.firstLetter;
}
// 联系人项
ListItem() {
ContactItem({ contact: contact })
}
}, (contact: Contact) => contact.id)
}
5. 实现滑动联动效果
添加列表滚动与字母导航栏的联动:
// 在Index组件中添加
private listController: ListController = new ListController();
// 修改List组件添加控制器和滚动事件
List({ space: 0, controller: this.listController }) {
// ...列表内容
}
.onScrollIndex((firstVisible: number) => {
if (firstVisible >= 0 && firstVisible < this.contacts.length) {
const currentContact = this.contacts[firstVisible];
this.currentLetter = currentContact.firstLetter;
}
})
// 修改scrollToLetter方法
scrollToLetter(letter: string) {
const index = this.contacts.findIndex(item => item.firstLetter === letter);
if (index >= 0) {
this.listController.scrollToIndex(index);
this.currentLetter = letter;
this.showLetterTip = true;
setTimeout(() => {
this.showLetterTip = false;
}, 1000);
} else {
promptAction.showToast({ message: `没有${letter}开头的联系人` });
}
}
6. 添加触摸交互效果
增强字母导航栏的触摸交互:
// 在Index组件中添加
@State isTouching: boolean = false;
// 修改字母导航栏Column
Column() {
ForEach(this.letters, (letter: string) => {
Text(letter)
.fontSize(14)
.fontColor(this.currentLetter === letter ? '#07C160' : '#666666')
.margin({ top: 2, bottom: 2 })
.onTouch((event: TouchEvent) => {
if (event.type === TouchType.Down || event.type === TouchType.Move) {
this.isTouching = true;
this.scrollToLetter(letter);
} else if (event.type === TouchType.Up) {
this.isTouching = false;
}
})
}, (letter: string) => letter)
}
.backgroundColor(this.isTouching ? 'rgba(0,0,0,0.1)' : 'rgba(0,0,0,0)')
.borderRadius(15)
7. 完整实现代码
整合所有功能的完整实现:
// Index.ets
import { Contact } from './Contact';
import promptAction from '@ohos.promptAction';
@Entry
@Component
struct Index {
private listController: ListController = new ListController();
@State contacts: Contact[] = [];
@State letters: string[] = [];
@State currentLetter: string = "";
@State showLetterTip: boolean = false;
@State isTouching: boolean = false;
onPageShow() {
this.loadContacts();
}
loadContacts() {
// 实际项目中应从联系人服务获取数据
const mockContacts = [
{id: "1", name: "Alice", avatar: "", phone: "13800138000"},
{id: "2", name: "Bob", avatar: "", phone: "13800138001"},
{id: "3", name: "Charlie", avatar: "", phone: "13800138002"},
// 更多联系人...
];
this.contacts = mockContacts.sort((a, b) => a.name.localeCompare(b.name));
this.generateLetters();
}
generateLetters() {
const letterSet = new Set<string>();
this.contacts.forEach(contact => {
letterSet.add(contact.firstLetter);
});
this.letters = Array.from(letterSet).sort();
}
scrollToLetter(letter: string) {
const index = this.contacts.findIndex(item => item.firstLetter === letter);
if (index >= 0) {
this.listController.scrollToIndex(index);
this.currentLetter = letter;
this.showLetterTip = true;
setTimeout(() => {
this.showLetterTip = false;
}, 1000);
} else {
promptAction.showToast({ message: `没有${letter}开头的联系人` });
}
}
build() {
Column() {
// 联系人列表
List({ space: 0, controller: this.listController }) {
let lastLetter = "";
ForEach(this.contacts, (contact: Contact) => {
if (contact.firstLetter !== lastLetter) {
ListItem() {
Text(contact.firstLetter)
.fontSize(18)
.fontColor('#999999')
.backgroundColor('#F5F5F5')
.width('100%')
.padding(10)
}
.sticky(Sticky.Normal)
lastLetter = contact.firstLetter;
}
ListItem() {
ContactItem({ contact: contact })
}
}, (contact: Contact) => contact.id)
}
.width('100%')
.layoutWeight(1)
.onScrollIndex((firstVisible: number) => {
if (firstVisible >= 0 && firstVisible < this.contacts.length) {
const currentContact = this.contacts[firstVisible];
this.currentLetter = currentContact.firstLetter;
}
})
// 字母导航栏
Column() {
ForEach(this.letters, (letter: string) => {
Text(letter)
.fontSize(14)
.fontColor(this.currentLetter === letter ? '#07C160' : '#666666')
.margin({ top: 2, bottom: 2 })
.onTouch((event: TouchEvent) => {
if (event.type === TouchType.Down || event.type === TouchType.Move) {
this.isTouching = true;
this.scrollToLetter(letter);
} else if (event.type === TouchType.Up) {
this.isTouching = false;
}
})
}, (letter: string) => letter)
}
.width(30)
.margin({ right: 10 })
.backgroundColor(this.isTouching ? 'rgba(0,0,0,0.1)' : 'rgba(0,0,0,0)')
.borderRadius(15)
.alignItems(HorizontalAlign.End)
// 字母提示框
if (this.showLetterTip) {
Text(this.currentLetter)
.fontSize(32)
.fontColor(Color.White)
.backgroundColor('#888888')
.opacity(0.8)
.padding(20)
.borderRadius(10)
.position({ x: '50%', y: '50%' })
.align(Alignment.Center)
}
}
.width('100%')
.height('100%')
}
}更多推荐



所有评论(0)