如何禁用CNContactPickerViewController中的联系功能区(消息、通话等)
如何移除/禁用CNContactPickerViewController中的联系功能区(消息、通话、视频、邮件)
嗨,我来帮你解决这个问题——首先得明确一点:CNContactPickerViewController并没有官方提供的API来直接隐藏或禁用这些系统自带的联系功能按钮,这些是苹果内置控件的默认交互元素,暂时没有开放修改权限。不过我们有两种可行的办法来达到类似的效果,一起来看看:
方案1:自定义联系人选择器(推荐)
如果想要完全摆脱那些功能按钮,最稳妥的方式就是自己实现一个联系人选择界面。我们可以用CNContactStore获取系统联系人数据,然后自定义UI和选择逻辑,这样就能完全控制界面上的所有元素。
给你一个简单的自定义picker示例代码:
import ContactsUI import Contacts class CustomContactPickerViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { private var contacts: [CNContact] = [] private let tableView = UITableView() private let contactStore = CNContactStore() override func viewDidLoad() { super.viewDidLoad() setupTableView() fetchContacts() } private func setupTableView() { tableView.frame = view.bounds tableView.dataSource = self tableView.delegate = self tableView.register(UITableViewCell.self, forCellReuseIdentifier: "ContactCell") view.addSubview(tableView) } private func fetchContacts() { // 定义需要获取的联系人属性 let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey, CNContactThumbnailImageDataKey] as [CNKeyDescriptor] let request = CNContactFetchRequest(keysToFetch: keysToFetch) do { try contactStore.enumerateContacts(with: request) { [weak self] contact, stop in self?.contacts.append(contact) } tableView.reloadData() } catch { print("获取联系人失败: \(error.localizedDescription)") } } // UITableView数据源方法 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return contacts.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ContactCell", for: indexPath) let contact = contacts[indexPath.row] cell.textLabel?.text = "\(contact.givenName) \(contact.familyName)" // 设置联系人头像 if let thumbnailData = contact.thumbnailImageData { cell.imageView?.image = UIImage(data: thumbnailData) } return cell } // 处理联系人选择事件 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let contact = contacts[indexPath.row] // 在这里实现你的业务逻辑,比如获取电话号码 if let phoneNumber = contact.phoneNumbers.first?.value { print(phoneNumber.stringValue) } dismiss(animated: true) } }
然后在你的ViewController里替换原来的picker调用:
@IBAction func pickerBtnAction(_ sender: Any) { let customPicker = CustomContactPickerViewController() present(customPicker, animated: true) }
方案2:拦截系统默认操作(仅阻止行为,无法隐藏按钮)
如果你不想完全自定义界面,也可以通过代理方法拦截用户点击功能按钮的默认行为,但这个方法只能阻止操作发生,无法隐藏那些按钮,而且后续系统版本可能会有变动,稳定性不如自定义方案。
只需要在你的CNContactPickerDelegate扩展中添加这个方法:
func contactPicker(_ picker: CNContactPickerViewController, shouldPerformDefaultActionFor contactProperty: CNContactProperty) -> Bool { // 返回false,阻止系统执行消息、通话等默认操作 return false }
修改后的完整代理代码如下:
extension ViewController: CNContactPickerDelegate { @IBAction func pickerBtnAction(_ sender: Any) { let contacVC = CNContactPickerViewController() contacVC.displayedPropertyKeys = [CNContactGivenNameKey, CNContactImageDataAvailableKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey, CNContactThumbnailImageDataKey, CNContactIdentifierKey] contacVC.hidesBottomBarWhenPushed = true contacVC.delegate = self self.present(contacVC, animated: true, completion: nil) } func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) { if let phone = contactProperty.value as? CNPhoneNumber { print(phone.stringValue) } } func contactPicker(_ picker: CNContactPickerViewController, shouldPerformDefaultActionFor contactProperty: CNContactProperty) -> Bool { // 拦截系统默认操作 return false } }
总结一下:如果需要彻底移除这些功能区,自定义联系人选择器是最佳选择;如果只是不想让这些按钮触发默认操作,可以用第二种方案临时应对。
内容的提问来源于stack exchange,提问作者Nawin Phunsawat
相关产品推荐
相关产品推荐

