UIImagePicker Controller & Delegate L3.4.1

Initializing a UIImagePickerController

@IBAction func pickAnImage(_ sender:Any) {

    let pickerController = UIImagePickerController()
    present(pickerController, animated: true, completion: nil)

}

UIImagePickerControllerDelegate

When the Image Picker Controller is presented one of two things can happen

  1. The user might select and image
  2. The user might cancel and close out

The delegate protocol is pretty straight forward with only two optional methods

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])  

Tells the delegate that the user picked a still image or movie.

func imagePickerControllerDidCancel(UIImagePickerController)  

Tells the delegate that the user cancelled the pick operation.

To be a delegate of the UIImagePickerController your View Controller class will also need to conform to the UINavigationControllerDelegate protocol. All of the methods in this protocol are also optional, so it can simply be added to the class declaration.

class ViewController: UIViewController, UIImagePickerControllerDelegate,  
UINavigationControllerDelegate {  
}

We can now launch the image picker, and see that the delegate methods are being called when we select an image, and when we cancel editing.

The image picker is no longer automatically dismissed though. To dismiss it explicitly, you can add the following to each of the delegate methods.

dismis(animated: true, completion: nil)  

How will the View Controller get access to the image?

We need to implement the two ImagePickerControllerDelegate methods to get access to an image chosen from the Photo library or camera.

The imagePickerController(_:didFinishPickingMediaWithInfo:) method is passed a dictionary as its second parameter. This dictionary contains UIImage objects and is of type [String: Any].

Below are the possible dictionary keys for the original version of the selected image.

let UIImagePickerControllerMediaType: String  

Specifies the media type selected by the user.

let UIImagePickerControllerOriginalImage: String  

Specifies the original, uncropped image selected by the user.

let UIImagePickerControllerEditedImage: String  

Specifies an image edited by the user.

let UIImagePickerControllerCropRect: String  

Specifies the cropping rectangle that was applied to the original image.

let UIImagePickerControllerMediaURL: String  

Specifies the filesystem URL for the movie.

let UIImagePickerControllerMediaMetadata: String  

Metadata for a newly-captured photograph.

let UIImagePickerControllerLivePhoto: String  

The Live Photo representation of the selected or captured photo.

The value in the info dictionary will be an optional type, and so it should be conditionally unwrapped. Here we use the conditional downcast operator as? to cast the value to a UIImage

 if let image = info[/* Dictionary Key Goes Here */] as? UIImage {
  imagePickerView.image = image
}

The image is distorted to fit the screen

By default UIImageViews stretch images to fit into their bounds, in most cases you will probably want to keep the original aspect ratio of the image and center it within the UIImageView. Different behaviors can be specified by setting the “content mode” of the UIImageView in the attributes inspector.

UIView Content Modes

Launching the Image Picker

To launch the camera and use a newly taken photo is almost identical to the code for picking an image from the album.

Setup an action method connected to the camera button just like the one for the album button, but this time adding the sourceType.

 @IBAction func pickAnImageFromCamera(_ sender: Any) {
  let imagePicker = UIImagePickerController()
  imagePicker.delegate = self
  imagePicker.sourceType = .photoLibrary
  present(imagePicker, animated: true, completion: nil)
}

Disabling the Camera Button

If the device being used doesn't have a camera the UIImagePickerController class has just the bool for the scenario isSourceTypeAvailable.

We want to disable the camera button in cases when this bool returns false for the sourceType. So we add the following to the viewWillAppear.

cameraButton.isEnabled = UIImagePickerController.isSourceTypeAvailable(.camera)