首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UIViewControllerRepresentable和CNContactPickerViewController

UIViewControllerRepresentable和CNContactPickerViewController
EN

Stack Overflow用户
提问于 2019-07-29 02:53:23
回答 5查看 6.3K关注 0票数 15

似乎无法创建一个与UIViewControllerRepresentable一起工作的CNContactPickerViewController。

使用Xcode 11 beta 4,我使用其他UIViewControllerRepresentable创建了许多其他UIViewController,这些UIViewController运行良好。我尝试过更改CNContactPickerViewController的特性和委托的不同实现。

代码语言:javascript
复制
import SwiftUI
import ContactsUI

// Minimal version
struct LookupContactVCR : UIViewControllerRepresentable {

    func makeUIViewController(context: Context) -> CNContactPickerViewController {
        let contactPickerVC = CNContactPickerViewController()
        contactPickerVC.delegate = context.coordinator
        return contactPickerVC
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }

    func updateUIViewController(_ uiViewController: CNContactPickerViewController, context: Context) {}

    class Coordinator: NSObject {}
}

extension LookupContactVCR.Coordinator : CNContactPickerDelegate {

    func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
        print("Chose: \(contact.givenName)")
    }
}

#if DEBUG
struct LookupContact_Previews : PreviewProvider {
    static var previews: some View {
        LookupContactVCR()
    }
}
#endif

没有错误信息。但是屏幕总是白色的,没有任何渲染。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2019-08-23 07:31:12

首先,请为这个问题提交一份Bug报告。1:https://bugreport.apple.com

其次,对于这个问题,有2的解决方案

  1. 您可以使用不推荐但仍然有效的ABPeoplePickerNavigationController
  2. 创建一个UIViewController,它在viewWillAppear上显示CNContactPickerViewController,并与SwiftUI一起使用这个新创建的视图控制器。

1. ABPeoplePickerNavigationController

代码语言:javascript
复制
import SwiftUI
import AddressBookUI

struct PeoplePicker: UIViewControllerRepresentable {
    typealias UIViewControllerType = ABPeoplePickerNavigationController

    final class Coordinator: NSObject, ABPeoplePickerNavigationControllerDelegate, UINavigationControllerDelegate {
        func peoplePickerNavigationController(_ peoplePicker: ABPeoplePickerNavigationController, didSelectPerson person: ABRecord) {
            <#selected#>
        }
        
        func peoplePickerNavigationControllerDidCancel(_ peoplePicker: ABPeoplePickerNavigationController) {
            <#cancelled#>
        }
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }

    func makeUIViewController(context: UIViewControllerRepresentableContext<PeoplePicker>) -> PeoplePicker.UIViewControllerType {
        let result = UIViewControllerType()
        result.delegate = context.coordinator
        return result
    }
    
    func updateUIViewController(_ uiViewController: PeoplePicker.UIViewControllerType, context: UIViewControllerRepresentableContext<PeoplePicker>) { }

}

2. CNContactPickerViewController

EmbeddedContactPickerViewController

代码语言:javascript
复制
import Foundation
import ContactsUI
import Contacts

protocol EmbeddedContactPickerViewControllerDelegate: AnyObject {
    func embeddedContactPickerViewControllerDidCancel(_ viewController: EmbeddedContactPickerViewController)
    func embeddedContactPickerViewController(_ viewController: EmbeddedContactPickerViewController, didSelect contact: CNContact)
}

class EmbeddedContactPickerViewController: UIViewController, CNContactPickerDelegate {
    weak var delegate: EmbeddedContactPickerViewControllerDelegate?
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.open(animated: animated)
    }
    
    private func open(animated: Bool) {
        let viewController = CNContactPickerViewController()
        viewController.delegate = self
        self.present(viewController, animated: false)
    }
    
    func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
        self.dismiss(animated: false) {
            self.delegate?.embeddedContactPickerViewControllerDidCancel(self)
        }
    }
    
    func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
        self.dismiss(animated: false) {
            self.delegate?.embeddedContactPickerViewController(self, didSelect: contact)
        }
    }
    
}

EmbeddedContactPicker

代码语言:javascript
复制
import SwiftUI
import Contacts
import Combine

struct EmbeddedContactPicker: UIViewControllerRepresentable {
    typealias UIViewControllerType = EmbeddedContactPickerViewController
    
    final class Coordinator: NSObject, EmbeddedContactPickerViewControllerDelegate {
        func embeddedContactPickerViewController(_ viewController: EmbeddedContactPickerViewController, didSelect contact: CNContact) {
            <#selected#>
        }
        
        func embeddedContactPickerViewControllerDidCancel(_ viewController: EmbeddedContactPickerViewController) {
            <#cancelled#>
        }
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }

    func makeUIViewController(context: UIViewControllerRepresentableContext<EmbeddedContactPicker>) -> EmbeddedContactPicker.UIViewControllerType {
        let result = EmbeddedContactPicker.UIViewControllerType()
        result.delegate = context.coordinator
        return result
    }
    
    func updateUIViewController(_ uiViewController: EmbeddedContactPicker.UIViewControllerType, context: UIViewControllerRepresentableContext<EmbeddedContactPicker>) { }

}
票数 12
EN

Stack Overflow用户

发布于 2021-01-05 21:21:32

我所做的就是把它封装在一个NavigationController里。也许不像阿图里戈的回答那么干净,但工作起来很容易。

代码语言:javascript
复制
func makeUIViewController(context: Context) -> some UIViewController {
    // needs to be wrapper in another controller. Else isn't displayed
    let navController = UINavigationController()
    let controller = CNContactPickerViewController()
    controller.delegate = delegate

    controller.predicateForEnablingContact = enablingPredicate

    navController.present(controller, animated: false, completion: nil)
    return navController
}

关于问题,它应该如何显示。我只是有条件地将其显示为组内的视图。

代码语言:javascript
复制
Group {
    Text("Sharing is caring")

    if showContactPicker {
        ContactPicker(contactType: .email)
    }
}
票数 2
EN

Stack Overflow用户

发布于 2021-03-09 22:19:20

@youjin解决方案与navigationView一起在工作表中使用时会出现问题。

例如,首先我呈现一个.sheet视图,在我拥有的sheet视图中,并将作为子视图,然后,在所有这些视图中,我呈现了Contact Picker。对于此场景,当联系Picker解散时,也请取消我的工作表视图父级。

我添加了一个@Environment(\.presentationMode)变量,并使用Coordinator方法取消了操作。看看我的解决方案:

代码语言:javascript
复制
import SwiftUI
import ContactsUI

/**
Presents a CNContactPickerViewController view modally.
- Parameters:
    - showPicker: Binding variable for presenting / dismissing the picker VC
    - onSelectContact: Use this callback for single contact selection
    - onSelectContacts: Use this callback for multiple contact selections
*/
public struct ContactPicker: UIViewControllerRepresentable {
    @Environment(\.presentationMode) var presentationMode
    
    @Binding var showPicker: Bool
    @State private var viewModel = ContactPickerViewModel()
    public var onSelectContact: ((_: CNContact) -> Void)?
    public var onSelectContacts: ((_: [CNContact]) -> Void)?
    public var onCancel: (() -> Void)?
    
    public init(showPicker: Binding<Bool>, onSelectContact: ((_: CNContact) -> Void)? = nil, onSelectContacts: ((_: [CNContact]) -> Void)? = nil, onCancel: (() -> Void)? = nil) {
        self._showPicker = showPicker
        self.onSelectContact = onSelectContact
        self.onSelectContacts = onSelectContacts
        self.onCancel = onCancel
    }
    
    public func makeUIViewController(context: UIViewControllerRepresentableContext<ContactPicker>) -> ContactPicker.UIViewControllerType {
        let dummy = _DummyViewController()
        viewModel.dummy = dummy
        return dummy
    }
    
    public func updateUIViewController(_ uiViewController: _DummyViewController, context: UIViewControllerRepresentableContext<ContactPicker>) {

        guard viewModel.dummy != nil else {
            return
        }
        
        // able to present when
        // 1. no current presented view
        // 2. current presented view is being dismissed
        let ableToPresent = viewModel.dummy.presentedViewController == nil || viewModel.dummy.presentedViewController?.isBeingDismissed == true
        
        // able to dismiss when
        // 1. cncpvc is presented
        let ableToDismiss = viewModel.vc != nil
        
        if showPicker && viewModel.vc == nil && ableToPresent {
            let pickerVC = CNContactPickerViewController()
            pickerVC.delegate = context.coordinator
            viewModel.vc = pickerVC
            viewModel.dummy.present(pickerVC, animated: true)
        } else if !showPicker && ableToDismiss {
//            viewModel.dummy.dismiss(animated: true)
            self.viewModel.vc = nil
        }
    }
    
    public func makeCoordinator() -> Coordinator {
        if self.onSelectContacts != nil {
            return MultipleSelectionCoordinator(self)
        } else {
            return SingleSelectionCoordinator(self)
        }
    }
    
    public final class SingleSelectionCoordinator: NSObject, Coordinator {
        var parent : ContactPicker
        
        init(_ parent: ContactPicker){
            self.parent = parent
        }
        
        public func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
            parent.showPicker = false
            parent.onCancel?()
        }
        
        public func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
            parent.showPicker = false
            parent.onSelectContact?(contact)
        }
    }
    
    public final class MultipleSelectionCoordinator: NSObject, Coordinator {
        var parent : ContactPicker
        
        init(_ parent: ContactPicker){
            self.parent = parent
        }
        
        public func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
            parent.showPicker = false
            parent.onCancel?()
            parent.presentationMode.wrappedValue.dismiss()
        }
        
        public func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
            parent.showPicker = false
            parent.onSelectContacts?(contacts)
            parent.presentationMode.wrappedValue.dismiss()
        }
    }
}

class ContactPickerViewModel {
    var dummy: _DummyViewController!
    var vc: CNContactPickerViewController?
}

public protocol Coordinator: CNContactPickerDelegate {}

public class _DummyViewController: UIViewController {}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57246685

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档