I am developing an iphone application where I directly use AVFoundation to capture videos via the camera.
I\'ve implemented a feature to enable the tap to focus>
Here's a basic Swift view that will show an animated focus square. Just add it to your camera view and hook it up to the focus callback from a tap gesture recognizer.
@objc func didTapToFocus(gesture: UITapGestureRecognizer) {
let pointInViewCoordinates = gesture.location(in: gesture.view)
let pointInCameraCoordinates = cameraView.videoPreviewLayer.captureDevicePointConverted(fromLayerPoint: pointInViewCoordinates)
camera.focusOn(pointInCameraCoordinates: pointInCameraCoordinates)
cameraView.showFocusBox(at: pointInViewCoordinates)
}
Focus view:
final class CameraFocusBoxView: UIView {
// MARK: - Instantiation
init() {
super.init(frame: .zero)
backgroundColor = .clear
layer.addSublayer(focusBoxLayer)
}
// MARK: - API
/// This zooms/fades in a focus square and blinks it a few times, then slowly fades it out
func showBox(at point: CGPoint) {
focusBoxLayer.removeAllAnimations()
let scaleKey = "zoom in focus box"
let fadeInKey = "fade in focus box"
let pulseKey = "pulse focus box"
let fadeOutKey = "fade out focus box"
guard focusBoxLayer.animation(forKey: scaleKey) == nil,
focusBoxLayer.animation(forKey: fadeInKey) == nil,
focusBoxLayer.animation(forKey: pulseKey) == nil,
focusBoxLayer.animation(forKey: fadeOutKey) == nil
else { return }
CATransaction.begin()
CATransaction.setDisableActions(true)
focusBoxLayer.position = point
CATransaction.commit()
let scale = CABasicAnimation(keyPath: "transform.scale")
scale.fromValue = 1
scale.toValue = 0.375
scale.duration = 0.3
scale.isRemovedOnCompletion = false
scale.fillMode = .forwards
let opacityFadeIn = CABasicAnimation(keyPath: "opacity")
opacityFadeIn.fromValue = 0
opacityFadeIn.toValue = 1
opacityFadeIn.duration = 0.3
opacityFadeIn.isRemovedOnCompletion = false
opacityFadeIn.fillMode = .forwards
let pulsing = CABasicAnimation(keyPath: "borderColor")
pulsing.toValue = UIColor(white: 1, alpha: 0.5).cgColor
pulsing.repeatCount = 2
pulsing.duration = 0.2
pulsing.beginTime = CACurrentMediaTime() + 0.3 // wait for the fade in to occur
let opacityFadeOut = CABasicAnimation(keyPath: "opacity")
opacityFadeOut.fromValue = 1
opacityFadeOut.toValue = 0
opacityFadeOut.duration = 0.5
opacityFadeOut.beginTime = CACurrentMediaTime() + 2 // seconds
opacityFadeOut.isRemovedOnCompletion = false
opacityFadeOut.fillMode = .forwards
focusBoxLayer.add(scale, forKey: scaleKey)
focusBoxLayer.add(opacityFadeIn, forKey: fadeInKey)
focusBoxLayer.add(pulsing, forKey: pulseKey)
focusBoxLayer.add(opacityFadeOut, forKey: fadeOutKey)
}
// MARK: - Private Properties
private lazy var focusBoxLayer: CALayer = {
let box = CALayer()
box.bounds = CGRect(x: 0, y: 0, width: 200, height: 200)
box.borderWidth = 2
box.borderColor = UIColor.white.cgColor
box.opacity = 0
return box
}()
// MARK: - Unsupported Initializers
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}