Reputation: 55865
It seems if you use UIViewControllerRepresentable
to implement a view controller in your SwiftUI app, when you present it via sheet
you cannot swipe to dismiss it. Is there something you need to do to support swipe to dismiss?
struct ContentView: View {
@State var showingPicker = false
var body: some View {
Text("Hello, world!")
.onAppear {
showingPicker = true
}
.sheet(isPresented: $showingPicker, content: {
PHPicker() //cannot swipe to dismiss
//Text("Test") //can swipe to dismiss
})
}
}
struct PHPicker: UIViewControllerRepresentable {
func makeUIViewController(context: UIViewControllerRepresentableContext<PHPicker>) -> PHPickerViewController {
let config = PHPickerConfiguration()
return PHPickerViewController(configuration: config)
}
func updateUIViewController(_ uiViewController: PHPickerViewController, context: UIViewControllerRepresentableContext<PHPicker>) { }
}
Upvotes: 6
Views: 1522
Reputation: 55865
iOS 17 allows swipe to dismiss for view controllers presented in sheets. You don’t need to do anything to enable this behavior. I tested with SFSafariViewController and MFMailComposeViewController.
Upvotes: 0
Reputation: 258461
Possible solution is to add something like handle to drag (no styling - simplified for demo),
.sheet(isPresented: $showingPicker, content: {
VStack {
RoundedRectangle(cornerRadius: 8).fill(Color.gray)
.frame(width: 60, height: 8)
.padding(.top, 8)
PHPicker()
}
})
Alternate: the solution is to make presentation by UIKit completely and just pass activation binding inside representable.
Here is a demo of possible approach. Tested with Xcode 12.1 / iOS 14.1
struct PHPickerContentView: View {
@State var showingPicker = false
var body: some View {
Button("Picker") {
showingPicker = true
}
.background(PHPicker(isPresented: $showingPicker)) // << here !!
}
}
struct PHPicker: UIViewControllerRepresentable {
@Binding var isPresented: Bool
func makeUIViewController(context: Context) -> UIViewController {
UIViewController() // << picker presenter
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
// react on binding & show if not shown
if isPresented && uiViewController.presentedViewController == nil {
let config = PHPickerConfiguration()
let picker = PHPickerViewController(configuration: config)
picker.delegate = context.coordinator
uiViewController.present(picker, animated: true)
picker.presentationController?.delegate = context.coordinator
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, PHPickerViewControllerDelegate, UIAdaptivePresentationControllerDelegate {
let owner: PHPicker
init(_ owner: PHPicker) {
self.owner = owner
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// picked image handling code here
picker.presentingViewController?.dismiss(animated: true)
owner.isPresented = false // << reset on action !!
}
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
owner.isPresented = false // << reset on swipe !!
}
}
}
Upvotes: 2