I need to open an image picker in my app using SwiftUI, how can I do that?
I thought about using the UIImagePickerController
, but I don't know how to do that in SwiftUI.
You need to wrap UIImagePickerController in a struct implementing UIViewControllerRepresentable . Here's a simple view to test it: The picker is displayed in a sheet. the selected image appears without any sort of animation, and replaces the Show image picker button.
To use a sheet, give it something to show (some text, an image, a custom view, etc), add a Boolean that defines whether the detail view should be showing, then attach it to your main view as a modal sheet. Important: If you're targeting iOS 14 or below, you should use @Environment(\.
You need to wrap UIImagePickerController
in a struct implementing UIViewControllerRepresentable
.
For more about UIViewControllerRepresentable
, please check this amazing WWDC 2019 talk:
Integrating SwiftUI
struct ImagePicker: UIViewControllerRepresentable { @Environment(\.presentationMode) private var presentationMode let sourceType: UIImagePickerController.SourceType let onImagePicked: (UIImage) -> Void final class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { @Binding private var presentationMode: PresentationMode private let sourceType: UIImagePickerController.SourceType private let onImagePicked: (UIImage) -> Void init(presentationMode: Binding<PresentationMode>, sourceType: UIImagePickerController.SourceType, onImagePicked: @escaping (UIImage) -> Void) { _presentationMode = presentationMode self.sourceType = sourceType self.onImagePicked = onImagePicked } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage onImagePicked(uiImage) presentationMode.dismiss() } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { presentationMode.dismiss() } } func makeCoordinator() -> Coordinator { return Coordinator(presentationMode: presentationMode, sourceType: sourceType, onImagePicked: onImagePicked) } func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController { let picker = UIImagePickerController() picker.sourceType = sourceType picker.delegate = context.coordinator return picker } func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) { } }
Here's a simple view to test it:
Show image picker
buttonstruct ContentView: View { @State var showImagePicker: Bool = false @State var image: Image? = nil var body: some View { ZStack { VStack { Button(action: { self.showImagePicker.toggle() }) { Text("Show image picker") } image?.resizable().frame(width: 100, height: 100) } .sheet(isPresented: $showImagePicker) { ImagePicker(sourceType: .photoLibrary) { image in self.image = Image(uiImage: image) } } } } }
I hope this helps as a starting point!
I'm sure Apple will make this easier to do once SwiftUI
is out of beta.
Tested on Xcode 11.4
Bugs:
sourceType
is not the camera. You won't be able to drag down the sheet - I haven't been able to find a solution yet.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With