SwiftUI 全屏 UIImagePickerController(相机)

Nic*_*hrn 7 uiimagepickercontroller swiftui

UIImagePickerController通过在修改器内部提供逻辑来在我的应用程序中呈现 a sheet。简而言之,以下三种类型处理显示和消除UIImagePickerController类型内部的实例UIViewControllerRepresentable,其按预期工作:

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

}
Run Code Online (Sandbox Code Playgroud)
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
    }
}
Run Code Online (Sandbox Code Playgroud)
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()
    }

}
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是相机视图是模态呈现的,它没有覆盖整个屏幕。当相机作为源时,这会导致UIImagePickerController布局有时看起来会被破坏,就好像相机不是为了以这种方式呈现一样。设置imagePicker.modalPresentationStyle = .fullScreen不会导致全屏演示。

带有相机源的 UIImagePickerController 的屏幕截图

如何以全屏布局显示相机,使其不出现卡片式的呈现方式?

ada*_*086 16

结合@LaX 和@GrandSteph 的答案,我有:

.fullScreenCover(isPresented: $activeSheet, content: {
    ImagePicker(image: $inputImage, sourceType: .camera)
       .edgesIgnoringSafeArea(.all)
 })
Run Code Online (Sandbox Code Playgroud)


Gra*_*eph 0

好吧,对这个答案持保留态度。我可能会因此而被投下地狱……但苹果也应该如此,因为它没有提供一种在 SwiftUI 中全屏显示 UIImagePickerController 的简单方法。

非常糟糕的技巧是在 rootView 中创建选择器并让它忽略安全区域。然后将所有必要的参数作为绑定传递到需要 imagePicker 的视图

struct mainView: View {

    @State private var imagePicked = UIImage()
    @State private var showImagePicker = false
    @State private var pickerSource = UIImagePickerController.SourceType.camera

    var body: some View {
        ZStack {
            AvatarView(showImagePicker: self.$showImagePicker, pickerSource: self.$pickerSource , imagePicked: self.$imagePicked)

            if self.showImagePicker {
                ImagePickerView(isPresented: self.$showImagePicker, selectedImage: self.$imagePicked, source: .camera).edgesIgnoringSafeArea(.all)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,您的 Avatar 视图将包含更新这些绑定所需的所有代码。像这样的东西

HStack () {
    Button(action: {
        self.showActionSheet.toggle()
    }) {
        MyImageView(image: self.imagePicked)
    }
    .actionSheet(isPresented: $showActionSheet, content: {
        ActionSheet(title: Text("Picture source"), buttons: [
            .default(Text("Camera"), action: {
                self.pickerSource = .camera
                self.showImagePicker.toggle()
            }),
            .default(Text("Photo Library"), action: {
                self.pickerSource = .photoLibrary
                self.showImagePicker.toggle()
            }),
            .destructive(Text("Cancel"))
        ])
    })
}
Run Code Online (Sandbox Code Playgroud)

老实说,我对是否提供这个解决方案犹豫不决,这段代码让我眼睛流血,但我认为有人在阅读本文时可能有更好的想法,并提供一种真正干净的 SwiftUI 方式来实现它。

这个解决方案的好处是它可以很好地管理方向的变化,让我们面对现实吧,UIImagePickerController 无法正确适应纸张。对于照片库来说还可以,但对于相机来说就不行了。