Solution for Ch 15 Bronze, Silver, and Gold Challenge

Bronze Challenge: Editing an Image

In DetailViewController.swift, in function takePicture(_:slight_smile: add the code below before presenting the image picker.

imagePicker.allowsEditing = true

After taking a photo, you can now zoom and crop the photo. To use the edited image, instead of the OriginalImage, update imagePickerController(_:didFinishPickingMediaWithInfo:)

//  let image = info[UIImagePickerControllerOriginalImage] as! UIImage
let image = info[UIImagePickerControllerEditedImage] as! UIImage

Silver Challenge: Removing an Image

In DetailViewController.swift, add the code below to class DetailViewController

var flexibleSpaceBarButton: UIBarButtonItem!
var removePictureBarButton: UIBarButtonItem!

override func viewDidLoad() {
  super.viewDidLoad()
  
  flexibleSpaceBarButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
  removePictureBarButton = UIBarButtonItem(
    barButtonSystemItem: .trash,
    target: self, action: #selector(removePicture(_:)))
  
  // Locate the toolbar at bottom and add to it the barButtons
  for subView in self.view.subviews {
    if let toolbar = subView as? UIToolbar {
      var toolbarItems = toolbar.items
      toolbarItems?.append(flexibleSpaceBarButton)
      toolbarItems?.append(removePictureBarButton)
      toolbar.setItems(toolbarItems, animated: true)
      break
    }
  }
}

@IBAction func removePicture(_ sender: UIBarButtonItem) {
  imageStore.deleteImage(forKey: item.itemKey)
  imageView.image = nil
  removePictureBarButton.isEnabled = false
}

Add the code below to the end of viewWillAppear(_:slight_smile:

removePictureBarButton.isEnabled = imageView.image != nil

Add the code below to the end of imagePickerController(_:didFinishPickingMediaWithInfo:)

removePictureBarButton.isEnabled = true

Gold Challenge: Camera Overlay

Note that the overlayView property can be accessed only when the source type of the image picker is set to camera. In DetailViewController.swift, update takePicture(_:slight_smile: as below

@IBAction func takePicture(_ sender: UIBarButtonItem) {
  let imagePicker = UIImagePickerController()
  // If the device has a camera, take a picture; otherwise,
  // just pick from photo library
  if UIImagePickerController.isSourceTypeAvailable(.camera) {
    imagePicker.sourceType = .camera
    
    let overlayView = UIView(frame: imagePicker.cameraOverlayView!.frame)
    
    let crosshairLabel = UILabel()
    crosshairLabel.text = "+"
    crosshairLabel.font = UIFont.systemFont(ofSize: 50)
    crosshairLabel.translatesAutoresizingMaskIntoConstraints = false
    overlayView.addSubview(crosshairLabel)
    
    crosshairLabel.centerXAnchor.constraint(equalTo: overlayView.centerXAnchor).isActive = true
    crosshairLabel.centerYAnchor.constraint(equalTo: overlayView.centerYAnchor).isActive = true
    
    // To avoid blocking the underneath default camera controls
    overlayView.isUserInteractionEnabled = false
    
    imagePicker.cameraOverlayView = overlayView
  } else {
    imagePicker.sourceType = .photoLibrary
  }
  
  imagePicker.delegate = self
  imagePicker.allowsEditing = true

  // Place image picker on the screen
  present(imagePicker, animated: true, completion: nil)
}
1 Like

Hi, how did you find/debug the need for this? I noticed that when I comment this out, I cannot select Retake or Use Photo after taking a shot, but it seems like this detail would be difficult for me to find in the documentation. Sorry to ask these kinds of questions, I just have not developed an intuition on where to find things in the documentation!

The cameraOverlayView is the view to display on top of the default image picker interface. As the exact positions of the default camera controls are unknown, it is not possible to determine the size of the cameraOverlayView beforehand so as not to block the underneath camera controls.

To make the cameraOverlayView as “transparent” as possible, set its isUserInteractionEnabled property to false. User touch can then pass through to the view below.

Hi. I don’t get it. The result of the code for the gold challenge should be seen on camera interface, or what? When I press the camera button, it opens a photo library, and there isn’t anything changed. Could you explain this challenge, please?

Code with camera function need to be tested on a real physical iDevice with a camera, e.g. a iPhone, a iPad. The camera function is not available in the simulator.

OK. Thank you very much!