Reading time: 1 min

This recipe shows how to add an image picker to your SwiftUI app. You'll do this by wrapping a UIKit UIImagePickerController in a UIViewControllerRepresentable. The end result looks like this:

Preview

This recipe is a part of our Road to DigitalSignatureView series, which explores various components vital to functioning of our SwiftUIDigitalSignature component.

OK, here's the code:

struct ImagePicker: UIViewControllerRepresentable {
  @Environment(\.presentationMode) private var presentationMode // allows you to dismiss the image picker overlay
  @Binding var selectedImage: UIImage // selected image binding
  @Binding var didSet: Bool // tells if the view was set or cancelled
  var sourceType = UIImagePickerController.SourceType.photoLibrary

  func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
    let imagePicker = UIImagePickerController()
    imagePicker.navigationBar.tintColor = .clear
    imagePicker.allowsEditing = false
    imagePicker.sourceType = sourceType
    imagePicker.delegate = context.coordinator
    return imagePicker
  }

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

  func makeCoordinator() -> Coordinator {
      Coordinator(self)
  }

  class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    let control: ImagePicker

    init(_ control: ImagePicker) {
      self.control = control
    }

    func imagePickerController(_ picker: UIImagePickerController,
                               didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
      if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
        control.selectedImage = image
        control.didSet = true
      }
      control.presentationMode.wrappedValue.dismiss()
    }
  }
}

Then, you can just wrap it in a popover and present it in your View:

struct SignatureImageView: View {
  @Binding var isSet: Bool
  @Binding var selection: UIImage

  @State private var showPopover = false

  var body: some View {
    Button(action: {
      showPopover.toggle()
     }) {
       if isSet {
         Image(uiImage: selection)
           .resizable()
           .frame(maxHeight: maxHeight)
       } else {
         ZStack {
           Color.white
           Text("Choose signature image")
             .font(.system(size: 18))
             .foregroundColor(.gray)
          }.frame(height: maxHeight)
          .overlay(RoundedRectangle(cornerRadius: 4)
                      .stroke(Color.gray))
       }
     }.popover(isPresented: $showPopover) {
       ImagePicker(selectedImage: $selection, didSet: $isSet)
     }
  }
}

Next Post Previous Post