In this episode we implement features that make the app feel more like a camera. When tapping the screen, we play the system camera shutter sound using AudioServices, then we add a small but useful flash effect to reinforce the fact the user took a photo. We'll also talk about a strategy for capturing the image by using a flag.
Episode Links iPhone Dev Wiki - Audio Services Tapping to take a photo To take a photo, we will use a UITapGestureRecognizer on the entire screen. override func viewDidLoad() { super.viewDidLoad() let tap = UITapGestureRecognizer(target: self, action: #selector(onTap(_:))) view.addGestureRecognizer(tap) } @objc func onTap(_ tap: UITapGestureRecognizer) { // play shutter sound // stop detecting new rectangles // flash // save photo } Playing the Shutter Sound To play the system camera shutter sound, we need to know the ID. Using the wiki link above, we found that this is 1108. We'll start by adding a constant at the top of the class: let cameraShutterSoundID: SystemSoundID = 1108 Then we use AudioServices to play the sound: @objc func onTap(_ tap: UITapGestureRecognizer) { // play shutter sound AudioServicesPlaySystemSound(cameraShutterSoundID) // ... } Displaying the Flash For this we'll create a full screen white layer and animate its opacity using Core Animation. private func flashScreen() { let flash = CALayer() flash.frame = view.bounds flash.backgroundColor = UIColor.white.cgColor view.layer.addSublayer(flash) flash.opacity = 0 let anim = CABasicAnimation(keyPath: "opacity") anim.fromValue = 0 anim.toValue = 1 anim.duration = 0.1 anim.autoreverses = true anim.isRemovedOnCompletion = true flash.add(anim, forKey: "flashAnimation") } We need to make sure to remove this layer when we're done, so we implement the animation delegate method in an extension. To do this we'll need to set ourselves up as the delegate, conform to the protocol, and stash away the created layer in a property so we can clean it up later. var flashLayer: CALayer? // in flashScreen() anim.delegate = self self.flashLayer = flash extension CaptureViewController : CAAnimationDelegate { func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { flashLayer?.removeFromSuperlayer() flashLayer = nil detectRectangles = true } } Finally we need to call this right after we play the sound: @objc func onTap(_ tap: UITapGestureRecognizer) { // play shutter sound AudioServicesPlaySystemSound(cameraShutterSoundID) // stop detecting rectangles // flash flashScreen() }