
This video is only available to subscribers. Start a subscription today to get access to this and 472 other videos.
Adding a Flash Toggle Camera Control
This episode is part of a series: Camera Capture and Detection.
1. Intro 1 min |
2. Setting Up The Project 9 min |
3. Camera Preview and Sample Buffer 10 min |
4. Drawing on Top of the Video Preview 14 min |
5. Fixing the Coordinates 7 min |
6. Perspective Outlining 9 min |
7. Camera Sounds and UI 12 min |
8. Rendering the Final Image 15 min |
9. Capturing High Resolution Photos 17 min |
10. Adding a Flash Toggle Camera Control 12 min |
Links
- Designing Icons with Sketch - Watch the episode where we design this flash
- AVCaptureDevice Documentation
Creating a Flash Control
For the flash button I want some behavior to be encapsulated in a separate class so we don't muddy up our view controller. This button class will be responsible for controlling how large the tap area of the button should be (not allowing the image to drive how big the button is) as well as toggling between the 2 flash icons.
class FlashButton : UIButton {
let TapSize = 50
override class var requiresConstraintBasedLayout: Bool { return true }
init() {
super.init(frame: CGRect(x: 0, y: 0, width: TapSize, height: TapSize))
tintColor = .white
translatesAutoresizingMaskIntoConstraints = false
adjustsImageWhenHighlighted = false
setImage(#imageLiteral(resourceName: "Flash"), for: .normal)
setImage(#imageLiteral(resourceName: "NoFlash"), for: .selected)
imageView?.contentMode = .center
addTarget(self, action: #selector(onFlashTapped), for: .touchUpInside)
}
override var intrinsicContentSize: CGSize {
return CGSize(width: TapSize, height: TapSize)
}
required init?(coder aDecoder: NSCoder) {
fatalError()
}
@objc func onFlashTapped() {
isSelected = !isSelected
}
}
Moving Our Camera Preview Layer Into a New Class
By moving this preview layer as a sublayer of a different view's layer, we can once again properly add subviews to our main view controller's view. This will be useful for drawing the flash button on top.
class CameraView : UIView {
let previewLayer: AVCaptureVideoPreviewLayer!
init(captureSession: AVCaptureSession) {
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.backgroundColor = UIColor.black.cgColor
previewLayer.videoGravity = .resizeAspect
super.init(frame: UIScreen.main.bounds)
layer.addSublayer(previewLayer)
setNeedsLayout()
layoutIfNeeded()
}
required init?(coder aDecoder: NSCoder) {
fatalError()
}
override func layoutSubviews() {
super.layoutSubviews()
previewLayer.frame = layer.bounds
}
}
Controlling the Torch
Before we can turn the camera's torch on or off we have to acquire a lock. This call can throw (if the device is busy or another application currently has the lock) so we'll create a quick helper function that will take care of this for us:
func withDeviceLock(on device: AVCaptureDevice, block: (AVCaptureDevice) -> Void) {
do {
try device.lockForConfiguration()
block(device)
device.unlockForConfiguration()
} catch {
// can't acquire lock
}
}
To turn the torch on:
func turnOnTorch(device: AVCaptureDevice) {
guard device.hasTorch else { return }
withDeviceLock(on: device) {
try? $0.setTorchModeOn(level: AVCaptureDevice.maxAvailableTorchLevel)
}
}
And to turn it off:
func turnOffTorch(device: AVCaptureDevice) {
guard device.hasTorch else { return }
withDeviceLock(on: device) {
$0.torchMode = .off
}
}