Search code examples
swiftuicncontactviewcontroller

SwiftUI - CNContactViewController NavigationBar problem


I am trying to implement CNContactViewDelegate to be able to show detail of the CNContact. And apparently, I am the first one to implement it with SwiftUI and getting problems. Anyway, I can see the detail of CNContact with using UIViewControllerRepresentable but I have an issue with the NavigationBar, which there is gap between the Contact's image and StatusBar -because of the NavigationBar and NavigationLink I think- and this gap is not there in the native Contacts app and apparently in this link that implemented the framework in UIKit.

Here is the code;

struct ContactsListView: View {
    @ObservedObject var contactsModel: ContactsViewModel
    var body: some View {
        NavigationView{
            List {
                //After some ForEach's and Section's
                //This view is working. 
                NavigationLink(destination: ContactDetailView(contact: self.$contactsModel.contacts[sectionIdx].contacts[contactIdx])) {
                    Text(self.contactsModel.contacts[sectionIdx].contacts[contactIdx].givenName)
                }
            }
            .navigationBarTitle("Contacts")
        }
    }
}


struct ContactView: UIViewControllerRepresentable {

    @Binding var contact: CNContact

    func makeCoordinator() -> ContactView.Coordinator {
        Coordinator(self)
    }

    func makeUIViewController(context: UIViewControllerRepresentableContext<ContactView>) -> CNContactViewController {
        let controller = CNContactViewController(for: contact)
        self.navigationBarHidden(true)
        return controller
    }

    func updateUIViewController(_ uiViewController: CNContactViewController, context: UIViewControllerRepresentableContext<ContactView>) {
        print(context)
    }

    class Coordinator: NSObject, CNContactViewControllerDelegate {

        var parent: ContactView

        init(_ contactDetail: ContactView) {
            self.parent = contactDetail
            self.parent.navigationBarHidden(true)

        }
    }
}

In the ContactView, both of those self.navigationBarHidden(true)'s are not working. As an example of the problem here is the native app's screenshot;

enter image description here

And here is the result of my code;

enter image description here


Solution

  • As the question is got an upvote I thought I can share my half way solution. This solves the gap however during the transition to detail there is a glitch of navigation bar with background color. After the transition it is becoming clear.

    struct ContactDetailView:  View {
    
        var contact: CNContact
    
        var body: some View {
            ZStack {
                Color.clear
                ContactView(contact: self.contact)
                    .navigationBarTitle("", displayMode: .inline)
            }.edgesIgnoringSafeArea(.top)
        }
    }
    
    struct ContactView: UIViewControllerRepresentable {
    
        var contact: CNContact
    
        func makeCoordinator() -> ContactView.Coordinator {
            Coordinator(self)
        }
    
        func makeUIViewController(context: UIViewControllerRepresentableContext<ContactView>) -> CNContactViewController {
            let controller = CNContactViewController(forUnknownContact: contact)
            controller.allowsActions = true
            controller.allowsEditing = false
            controller.delegate = context.coordinator
            return controller
        }
    
        func updateUIViewController(_ uiViewController: CNContactViewController, context: UIViewControllerRepresentableContext<ContactView>) {
            print("updated")
        }
    
        class Coordinator: NSObject, CNContactViewControllerDelegate {
    
            var parent: ContactView
    
            init(_ contactDetail: ContactView) {
                self.parent = contactDetail
            }
    
            func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
            }
    
            func contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) -> Bool {
    
                return true
            }
        }
    }