简体   繁体   中英

Support swipe to dismiss for UIViewControllerRepresentable presented in sheet

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>) { }
}

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

演示2

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 !!
        }
    }
}

backup

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM