Swiftui UIViewControllerRepresentable和CNContactPickServices控制器

Swiftui UIViewControllerRepresentable和CNContactPickServices控制器,swiftui,contactsui,Swiftui,Contactsui,似乎无法创建与CNContactPickerViewController一起使用的UIViewControllerRepresentable 使用Xcode 11 beta 4,我使用其他UIViewController创建了许多其他UIViewControllerRepresentable,这些都很好地工作。我已尝试更改CNContactPickerViewController的功能和委托的不同实现 导入快捷界面 进口合同 //最小版本 结构LookupContactVCR:UIViewCon

似乎无法创建与CNContactPickerViewController一起使用的UIViewControllerRepresentable

使用Xcode 11 beta 4,我使用其他UIViewController创建了许多其他UIViewControllerRepresentable,这些都很好地工作。我已尝试更改CNContactPickerViewController的功能和委托的不同实现

导入快捷界面
进口合同
//最小版本
结构LookupContactVCR:UIViewControllerRepresentable{
func makeUIViewController(上下文:context)->CNContactPickerViewController{
让contactPickerVC=CNContactPickerViewController()
contactPickerVC.delegate=context.coordinator
返回触点选择器
}
func makeCoordinator()->Coordinator{
返回协调员()
}
func updateUIViewController(uiViewController:CNContactPickerViewController,上下文:上下文){}
类协调器:NSObject{}
}
扩展查找ContactVCR。协调员:CNContactPickerDelegate{
func contactPicker(\ picker:CNContactPickerServices控制器,didSelect联系人:CNContact){
打印(“选择:\(contact.givenName)”)
}
}
#如果调试
结构查找联系人\u预览:PreviewProvider{
静态var预览:一些视图{
LookupContactVCR()
}
}
#恩迪夫

没有错误消息。但屏幕始终为白色,不显示任何内容。

首先,请为此问题提交一份文件。 其次,这个问题有两个解决办法:

  • 您可以使用
    ABPeoplePickerNavigationController
    ,该控制器已被弃用,但仍然有效
  • 创建一个
    UIViewController
    ,它在
    视图上显示
    CNContactPickerViewController
    ,并将此新创建的视图控制器与
    SwiftUI
    一起使用
  • 1.ABPeoplePickerNavigationController 嵌入式接触器选择器
    导入快捷界面
    导入联系人
    进口联合收割机
    结构EmbeddedContactPicker:UIViewControllerRepresentable{
    typealias UIViewControllerType=EmbeddedContactPickerViewController
    最后一个类协调器:NSObject,EmbeddedContactPickerWebController delegate{
    func embeddedContactPickerViewController(\uViewController:embeddedContactPickerViewController,didSelect联系人:CNContact){
    }
    func EmbeddedContactPickerViewController IDCancel(uu控制器:EmbeddedContactPickerViewController){
    }
    }
    func makeCoordinator()->Coordinator{
    返回协调员()
    }
    func makeUIViewController(上下文:UIViewControllerRepresentableContext)->EmbeddedContactPicker.UIViewControllerType{
    让结果=EmbeddedContactPicker.UIViewControllerType()
    result.delegate=context.coordinator
    返回结果
    }
    func updateUIViewController(uUIViewController:EmbeddedContactPicker.UIViewControllerType,上下文:UIViewControllerRepresentableContext){}
    }
    
    我所做的只是将其包装在NavigationController中。也许没有阿图里戈尔的答案那么清晰,但很容易奏效

    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
    }
    
    关于这些问题,应该如何显示。我只是有条件地将其显示为组内的视图

    Group {
        Text("Sharing is caring")
    
        if showContactPicker {
            ContactPicker(contactType: .email)
        }
    }
    

    @youjin解决方案在带有navigationView的工作表中使用时出现问题

    例如,首先,我呈现了一个
    .sheet
    视图,在这个工作表中,我有一个视图,并将导航视图作为子视图,然后,在所有这些视图中,我呈现了联系人选取器。对于这种情况,当联系选取者时解除,也解除我的图纸视图父视图

    我添加了一个
    @Environment(\.presentationMode)
    变量,并使用
    协调器
    方法取消了它。请看我的解决方案:

    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 {}
    
    导入快捷界面
    进口合同
    /**
    以模式显示CNContactPickerViewController视图。
    -参数:
    -showPicker:用于显示/取消选取器的绑定变量
    -onSelectContact:使用此回调选择单个联系人
    -onSelectContacts:将此回调用于多个联系人选择
    */
    公共结构联系人选择器:UIViewControllerRepresentable{
    @环境(\.presentationMode)变量presentationMode
    @绑定变量showPicker:Bool
    @State private var viewModel=ContactPickerViewModel()
    公共变量onSelectContact:(((_u:CNContact)->无效)?
    公共变量onSelectContacts:(([CNContact])->无效)?
    公共变量onCancel:(()->无效)?
    public init(showPicker:Binding,onSelectContacts:(((:CNContact)->Void)?=nil,onSelectContacts:(((:[CNContact])->Void)?=nil,onCancel:(()->Void)?=nil){
    self.\u showPicker=showPicker
    self.onSelectContact=onSelectContact
    self.onSelectContacts=onSelectContacts
    self.onCancel=onCancel
    }
    public func makeUIViewController(上下文:UIViewControllerRepresentableContext)->ContactPicker.UIViewControllerType{
    让dummy=\u DummyViewController()
    viewModel.dummy=虚拟
    返回假人
    }
    public func updateUIViewController(uiViewController:DummyViewController,上下文:UIViewControllerRepresentableContext){
    guard viewModel.dummy!=无其他{
    返回
    }
    //能够在
    //1.没有当前显示的视图
    //2.当前呈现的视图将被驳回
    设ableToPresent=viewModel.dummy.presentedViewController==nil | | | viewModel.dummy.presentedViewController?.IsBeingDisposed==true
    //能够在以下情况下解雇:
    //1.介绍了cncpvc
    设ableToDismiss=viewModel.vc!=nil
    如果showPicker&&viewModel.vc==nil&&ableToPresent{
    让pickerVC=CNContactPickerViewController()
    pickerVC.delegate=context.coordinator
    viewModel.vc=pickerVC
    viewMo
    
    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
    }
    
    Group {
        Text("Sharing is caring")
    
        if showContactPicker {
            ContactPicker(contactType: .email)
        }
    }
    
    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 {}