Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI Full-Screen UIImagePickerController (Camera)

I present a UIImagePickerController within my application by presenting it with logic inside of a sheet modifier. In short, the following three types handle displaying and dismissing a instance of UIImagePickerController inside of a UIViewControllerRepresentable type, which works as expected:

struct DetailsView: View {

    enum Sheet: Hashable, Identifiable {
        case takePhoto

        var id: Int { hashValue }
    }

    @State private var activeSheet: Sheet?

    var body: some View {
        Text("Hello, World!")
            .sheet(item: $activeSheet) { (sheet) in self.view(for: sheet) }
    }

    private func view(for sheet: Sheet) -> some View {
        switch sheet {
        case .takePhoto: return PhotoSelectionView(showImagePicker: .init(get: { sheet == .takePhoto }, set: { (show) in self.activeSheet = show ? .takePhoto : nil }), image: $selectedImage, photoSource: .camera).edgesIgnoringSafeArea(.all)
        }
    }

}
struct ImagePicker: UIViewControllerRepresentable {

    @Binding var isShown: Bool

    @Binding var image: Image?

    let photoSource: PhotoSource

    func makeCoordinator() -> ImagePickerCoordinator {
        return ImagePickerCoordinator(isShown: $isShown, selectedImage: $image)
    }

    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {

    } 

    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let imagePicker = UIImagePickerController()
        if photoSource == .camera, UIImagePickerController.isSourceTypeAvailable(.camera) {
            imagePicker.sourceType = .camera
            imagePicker.cameraCaptureMode = .photo
        }
        imagePicker.delegate = context.coordinator
        return imagePicker
    }
}
class ImagePickerCoordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

    @Binding private var isShown: Bool

    @Binding private var selectedImage: Image?

    init(isShown: Binding<Bool>, selectedImage: Binding<Image?>) {
        _isShown = isShown
        _selectedImage = selectedImage
    }

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        // handle photo selection 
    }

    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        dismiss()
    }

}

The issue that I am having is that the camera view is presented modally, which doesn't cover the entire screen. This causes the UIImagePickerController to appear to have broken layouts at times when the camera is the source, as if the camera was not made to be presented in this way. Setting imagePicker.modalPresentationStyle = .fullScreen does not result in a full-screen presentation.

Screenshot of UIImagePickerController with a camera source

How can I display the camera in a full-screen layout so that it does not appear in the card-like presentation style?

like image 948
Nick Kohrn Avatar asked Apr 22 '20 21:04

Nick Kohrn


2 Answers

combining @LaX and @GrandSteph's answers, I have:

.fullScreenCover(isPresented: $activeSheet, content: {
    ImagePicker(image: $inputImage, sourceType: .camera)
       .edgesIgnoringSafeArea(.all)
 })
like image 150
ada10086 Avatar answered Nov 08 '22 22:11

ada10086


With iOS 14 Apple has added the fullScreenCover(ispresented:ondismiss:content:) and fullScreenCover(item:ondismiss:content:) methods which do exactly what you are requesting.

From your example:

    var body: some View {
        Text("Hello, World!")
            .fullScreenCover(item: $activeSheet) { (sheet) in self.view(for: sheet) }
    }

Or, if you simply have a view you want to show:

   @State var customViewIsShown = false

    // ...

    var body: some View {
        Text("Hello, World!")
        .fullScreenCover(isPresented: $customViewIsShown) {
            YourCustomView(isShown: $customViewIsShown)
        }
    }
like image 22
LaX Avatar answered Nov 08 '22 23:11

LaX