如何在SwiftUI的ListView中正确显示通讯录电话号码?
如何在SwiftUI的ListView中正确显示通讯录联系人的电话号码?
现有代码已成功从通讯录获取并显示联系人的名字(givenName)与姓氏(familyName),但无法正确显示电话号码。以下是问题分析和修复方案:
当前代码
struct ContentView: View { @State var contacts:[CNContact] = [] var body: some View { VStack { Text("Conctacts") .font(.title) List { ForEach(contacts, id:\.self) { contact in VStack{ HStack{ Text("\(contact.givenName)") Text("\(contact.familyName)") .fontWeight(.bold) Spacer() Button { print("Edit button was tapped") } label: { Image(systemName:"person.crop.circle.fill.badge.plus") .font(.title3) .foregroundColor(.yellow) } .buttonStyle(.plain) } Text("\(contact.phoneNumbers[0])") } } } .onAppear{ Task.init{ await fetchAllContacts() } } } .padding() } func fetchAllContacts() async{ let store = CNContactStore() let keys = [CNContactGivenNameKey, CNContactPhoneNumbersKey, CNContactFamilyNameKey] as [CNKeyDescriptor] let fetchRequest = CNContactFetchRequest(keysToFetch: keys) do{ try store.enumerateContacts(with: fetchRequest, usingBlock: { contact, result in contacts.append(contact) }) } catch{ print ("Error") } } }
问题原因
CNContact.phoneNumbers是[CNLabeledValue<CNPhoneNumber>]类型数组,直接访问contact.phoneNumbers[0]并转成字符串,会输出CNLabeledValue的结构体信息而非实际电话号码。此外,直接取索引0还会有数组越界风险(如果联系人没有电话号码)。
修复方案
1. 提取电话号码字符串
每个CNLabeledValue的value属性是CNPhoneNumber类型,通过value.stringValue可以获取格式化后的电话号码。
2. 处理无号码的情况
先判断phoneNumbers数组是否为空,避免崩溃。
3. 可选:显示号码标签(如移动电话、家庭电话)
可以通过CNLabeledValue.label获取号码类型标签,用CNLabeledValue.localizedString(forLabel:)转成本地化显示文本。
修改后的代码
将原来的电话号码显示部分替换为以下内容,即可实现正常显示:
var body: some View { VStack { Text("Contacts") .font(.title) List { ForEach(contacts, id:\.self) { contact in VStack(alignment: .leading, spacing: 4) { HStack{ Text("\(contact.givenName)") Text("\(contact.familyName)") .fontWeight(.bold) Spacer() Button { print("Edit button was tapped") } label: { Image(systemName:"person.crop.circle.fill.badge.plus") .font(.title3) .foregroundColor(.yellow) } .buttonStyle(.plain) } // 显示所有关联的电话号码及标签 ForEach(contact.phoneNumbers, id: \.self) { phone in let phoneNumber = phone.value.stringValue let label = CNLabeledValue.localizedString(forLabel: phone.label ?? "") Text("\(label): \(phoneNumber)") .font(.subheadline) .foregroundColor(.gray) } // 无电话号码时显示提示 if contact.phoneNumbers.isEmpty { Text("无电话号码") .font(.subheadline) .foregroundColor(.gray) } } } } .onAppear{ Task{ await fetchAllContacts() } } } .padding() }
额外优化点
- 修正了标题拼写错误:
"Conctacts"改为"Contacts" - 调整VStack的对齐方式和间距,让布局更紧凑美观
内容的提问来源于stack exchange,提问作者fs_tigre
相关产品推荐
相关产品推荐

