In iOS18, Apple added a new view contactAccessPicker to help select contacts that are available to an app. The SwiftUI example shows how it should be used:
Button {
isPresented.toggle()
} label: {
Label("Add contacts", systemImage: "person.crop.circle.fill.badge.plus")
}
.contactAccessPicker(isPresented: $isPresented) { identifiers in
lastAddedContacts = Set(identifiers)
// Fetch all contacts the app has access to.
fetchContacts()
}
In my case, I have a UIKit app, so I need to use UIHostingController to show SwiftUI views. My 'button in this case is a UIBarButtonItem, and I would ideally like to show the contactAccessPicker presented on top of the view controller where that button is. But I'm not sure how I would handle this case where an "$isPresented" binding is needed to be shown, without having the problem of 'double presentation'. I.e. the simplest solution is to show a basic SwiftUI view (through UIHostingController) which then has this view modifier set on top of it. Here's an example:
struct CJContactAccessPickerHostedView: View {
@State private var isPickerPresented = true
var body: some View {
Text("Hello, World!")
.contactAccessPicker(isPresented: $isPickerPresented) { results in
print("Access picker results = \(results)")
}
}
}
Make it available to UIKit:
@objc static func makeContactsAccessPicker() -> UIViewController {
let hostcontroller = UIHostingController(rootView: CJContactAccessPickerHostedView())
hostcontroller.title = "Select Contacts"
return hostcontroller
}
Present in UIKit:
let rootViewController = SwiftUIViewFactory.makeContactsAccessPicker()
present(rootViewController, animated: true)
It works, but it first presents the SwiftUI view, and then it present the contactAccessPicker on top of that... causing a double presentation.
Is there a clean way to avoid that, and just show the contactAccessPicker view with the presentation binding through UIKit?
ObservableObjector anObservable,UIKitis the owner of the object and SwiftUI observes it.ObservableObjectand@ObservedObjectis the "better" solution because you can useCombineinUiKitif needed butObservableis the simplest. here