PhotoPicker/APLViewController.swift
/* |
Copyright (C) 2017 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
Main view controller for this application. |
*/ |
import UIKit |
import AVFoundation |
class APLViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate { |
@IBOutlet var imageView: UIImageView? |
@IBOutlet var cameraButton: UIBarButtonItem? |
@IBOutlet var overlayView: UIView? |
// Camera controls found in the overlay view. |
@IBOutlet var takePictureButton: UIBarButtonItem? |
@IBOutlet var startStopButton: UIBarButtonItem? |
@IBOutlet var delayedPhotoButton: UIBarButtonItem? |
@IBOutlet var doneButton: UIBarButtonItem? |
var imagePickerController = UIImagePickerController() |
var cameraTimer = Timer() |
var capturedImages = [UIImage]() |
// MARK: - View Life Cycle |
override func viewDidLoad() { |
super.viewDidLoad() |
imagePickerController.modalPresentationStyle = .currentContext |
imagePickerController.delegate = self |
// Remove the camera button if the camera is not currently available. |
if !UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) { |
toolbarItems = self.toolbarItems?.filter { $0 != cameraButton } |
} |
} |
override func didReceiveMemoryWarning() { |
super.didReceiveMemoryWarning() |
// Dispose of any resources that can be recreated. |
} |
fileprivate func finishAndUpdate() { |
dismiss(animated: true, completion: { [weak self] in |
guard let `self` = self else { |
return |
} |
if `self`.capturedImages.count > 0 { |
if self.capturedImages.count == 1 { |
// Camera took a single picture. |
`self`.imageView?.image = `self`.capturedImages[0] |
} else { |
// Camera took multiple pictures; use the list of images for animation. |
`self`.imageView?.animationImages = `self`.capturedImages |
`self`.imageView?.animationDuration = 5 // Show each captured photo for 5 seconds. |
`self`.imageView?.animationRepeatCount = 0 // Animate forever (show all photos). |
`self`.imageView?.startAnimating() |
} |
// To be ready to start again, clear the captured images array. |
`self`.capturedImages.removeAll() |
} |
}) |
} |
// MARK: - Toolbar Actions |
@IBAction func showImagePickerForCamera(_ sender: UIBarButtonItem) { |
let authStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video) |
if authStatus == AVAuthorizationStatus.denied { |
// Denied access to camera, alert the user. |
// The user has previously denied access. Remind the user that we need camera access to be useful. |
let alert = UIAlertController(title: "Unable to access the Camera", |
message: "To enable access, go to Settings > Privacy > Camera and turn on Camera access for this app.", |
preferredStyle: UIAlertControllerStyle.alert) |
let okAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) |
alert.addAction(okAction) |
let settingsAction = UIAlertAction(title: "Settings", style: .default, handler: { _ in |
// Take the user to Settings app to possibly change permission. |
guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else { return } |
if UIApplication.shared.canOpenURL(settingsUrl) { |
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in |
// Finished opening URL |
}) |
} |
}) |
alert.addAction(settingsAction) |
present(alert, animated: true, completion: nil) |
} |
else if (authStatus == AVAuthorizationStatus.notDetermined) { |
// The user has not yet been presented with the option to grant access to the camera hardware. |
// Ask for permission. |
// |
// (Note: you can test for this case by deleting the app on the device, if already installed). |
// (Note: we need a usage description in our Info.plist to request access. |
// |
AVCaptureDevice.requestAccess(for: AVMediaType.video, completionHandler: { (granted) in |
if granted { |
DispatchQueue.main.async { |
self.showImagePicker(sourceType: UIImagePickerControllerSourceType.camera, button: sender) |
} |
} |
}) |
} else { |
// Allowed access to camera, go ahead and present the UIImagePickerController. |
showImagePicker(sourceType: UIImagePickerControllerSourceType.camera, button: sender) |
} |
} |
@IBAction func showImagePickerForPhotoPicker(_ sender: UIBarButtonItem) { |
showImagePicker(sourceType: UIImagePickerControllerSourceType.photoLibrary, button: sender) |
} |
fileprivate func showImagePicker(sourceType: UIImagePickerControllerSourceType, button: UIBarButtonItem) { |
// If the image contains multiple frames, stop animating. |
if (imageView?.isAnimating)! { |
imageView?.stopAnimating() |
} |
if capturedImages.count > 0 { |
capturedImages.removeAll() |
} |
imagePickerController.sourceType = sourceType |
imagePickerController.modalPresentationStyle = |
(sourceType == UIImagePickerControllerSourceType.camera) ? |
UIModalPresentationStyle.fullScreen : UIModalPresentationStyle.popover |
let presentationController = imagePickerController.popoverPresentationController |
presentationController?.barButtonItem = button // Display popover from the UIBarButtonItem as an anchor. |
presentationController?.permittedArrowDirections = UIPopoverArrowDirection.any |
if sourceType == UIImagePickerControllerSourceType.camera { |
// The user wants to use the camera interface. Set up our custom overlay view for the camera. |
imagePickerController.showsCameraControls = false |
// Apply our overlay view containing the toolar to take pictures in various ways. |
overlayView?.frame = (imagePickerController.cameraOverlayView?.frame)! |
imagePickerController.cameraOverlayView = overlayView |
} |
present(imagePickerController, animated: true, completion: { |
// Done presenting. |
}) |
} |
// MARK: - Camera View Actions |
@IBAction func done(_ sender: UIBarButtonItem) { |
if cameraTimer.isValid { |
cameraTimer.invalidate() |
} |
finishAndUpdate() |
} |
@IBAction func takePhoto(_ sender: UIBarButtonItem) { |
imagePickerController.takePicture() |
} |
@IBAction func delayedTakePhoto(_ sender: UIBarButtonItem) { |
// These controls can't be used until the photo has been taken. |
doneButton?.isEnabled = false |
takePictureButton?.isEnabled = false |
delayedPhotoButton?.isEnabled = false |
startStopButton?.isEnabled = false |
let fireDate = Date(timeIntervalSinceNow: 5) |
cameraTimer = Timer.init(fire: fireDate, interval: 1.0, repeats: false, block: { timer in |
self.imagePickerController.takePicture() |
self.doneButton?.isEnabled = true |
self.takePictureButton?.isEnabled = true |
self.delayedPhotoButton?.isEnabled = true |
self.startStopButton?.isEnabled = true |
}) |
RunLoop.main.add(cameraTimer, forMode: RunLoopMode.defaultRunLoopMode) |
} |
@IBAction func startTakingPicturesAtIntervals(_ sender: UIBarButtonItem) { |
/* |
Start the timer to take a photo every 1.5 seconds. |
CAUTION: for the purpose of this sample, we will continue to take pictures indefinitely. |
Be aware we will run out of memory quickly. You must decide the proper threshold number of |
photos allowed to take from the camera. One solution to avoid memory constraints is to save each |
taken photo to disk rather than keeping all of them in memory. In low memory situations sometimes |
our "didReceiveMemoryWarning" method will be called in which case we can recover some memory |
and keep the app running. |
*/ |
// Change the button to represent "Stop" taking pictures. |
startStopButton?.title = NSLocalizedString("Stop", comment: "Title for overlay view controller start/stop button") |
startStopButton?.action = #selector(stopTakingPicturesAtIntervals) |
// These buttons can be working while we are running. |
doneButton?.isEnabled = false |
delayedPhotoButton?.isEnabled = false |
takePictureButton?.isEnabled = false |
// Start taking pictures right away. |
cameraTimer = Timer.scheduledTimer(withTimeInterval: 1.5, repeats: true) { timer in |
self.imagePickerController.takePicture() |
} |
} |
@IBAction func stopTakingPicturesAtIntervals(_ sender: UIBarButtonItem) { |
// Stop and reset the timer. |
cameraTimer.invalidate() |
finishAndUpdate() |
// Make these buttons available again. |
self.doneButton?.isEnabled = true |
self.takePictureButton?.isEnabled = true |
self.delayedPhotoButton?.isEnabled = true |
// Reset the button back to start taking pictures again. |
startStopButton?.title = NSLocalizedString("Start", comment: "Title for overlay view controller start/stop button") |
startStopButton?.action = #selector(startTakingPicturesAtIntervals) |
} |
// MARK: - UIImagePickerControllerDelegate |
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { |
let image = info[UIImagePickerControllerOriginalImage] |
capturedImages.append(image as! UIImage) |
if !cameraTimer.isValid { |
// Timer is done firing so Finish up until the user stops the timer from taking photos. |
finishAndUpdate() |
} |
} |
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { |
dismiss(animated: true, completion: { |
// Done cancel dismiss of image picker. |
}) |
} |
} |
Copyright © 2018 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2018-01-11