swiftswiftuiuiimagepickercontroller

New PhotosPicker in SwiftUI can open camera instead of the photoLibrary


is there any way to make the new PhotosPicker open the camera instead of opening the photoLibrary, I remember in the old UIImagePickerController there was this option user could choose in the picker if use camera or select from picture.


ImagePikerCircular(im: im, dataImage: $dataImage)
            .overlay(alignment: .bottomTrailing) {
                PhotosPicker(selection: $im.imageSelection,
                             matching: .images,
                             photoLibrary: .shared()) {
                    Image(systemName: "pencil.circle.fill")
                        .symbolRenderingMode(.multicolor)
                        .font(.system(size: 30))
                        .foregroundColor(.accentColor)
                }
                .buttonStyle(.borderless)
                .photosPickerStyle(.presentation)
            }


Solution

  • No, there is no way to open the camera using the PhotosPicker, you will need to create your own selection dialog and when the user taps the camera, open the old UIImagePickerController, you can create a UIViewControllerRepresentable like this:

    struct CameraPickerView: UIViewControllerRepresentable {
        
        private var sourceType: UIImagePickerController.SourceType = .camera
        private let onImagePicked: (UIImage) -> Void
        
        @Environment(\.presentationMode) private var presentationMode
        
        public init(onImagePicked: @escaping (UIImage) -> Void) {
            self.onImagePicked = onImagePicked
        }
        
        public func makeUIViewController(context: Context) -> UIImagePickerController {
            let picker = UIImagePickerController()
            picker.sourceType = self.sourceType
            picker.delegate = context.coordinator
            return picker
        }
        
        public func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
        
        public func makeCoordinator() -> Coordinator {
            Coordinator(
                onDismiss: { self.presentationMode.wrappedValue.dismiss() },
                onImagePicked: self.onImagePicked
            )
        }
        
        final public class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
            
            private let onDismiss: () -> Void
            private let onImagePicked: (UIImage) -> Void
            
            init(onDismiss: @escaping () -> Void, onImagePicked: @escaping (UIImage) -> Void) {
                self.onDismiss = onDismiss
                self.onImagePicked = onImagePicked
            }
            
            public func imagePickerController(_ picker: UIImagePickerController,
                                              didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
                if let image = info[.originalImage] as? UIImage {
                    self.onImagePicked(image)
                }
                self.onDismiss()
            }
            public func imagePickerControllerDidCancel(_: UIImagePickerController) {
                self.onDismiss()
            }
        }
    }
    

    Then, you can present the picker with a fullScreenCover:

    .fullScreenCover(isPresented: $showCameraPicker) {
        CameraPickerView() { image in
            // Do what you want with your image.
        }
    }
    

    source