swiftuiimagepickercontrollercameraoverlayview

Custom shutter button in cameraOverlayView not executing


I am making a custom camera in Swift. I declared it global like this:

let image = UIImagePickerController()

I have made OverlayVC (UIViewController) in IB. Made a shutter button and hooked it up like this:

@IBAction func shutterTapped(_ sender: Any) {
    print("shutterTapped")
    image.takePicture()
}

I instantiate this overlay before presenting:

image.delegate = self
image.sourceType = .camera
image.cameraDevice = .front
image.allowsEditing = false
let overlay = self.storyboard?.instantiateViewController(withIdentifier: "OverlayVC")
image.cameraOverlayView = overlay?.view
image.showsCameraControls = false
self.present(image, animated: true, completion: nil)

Now when I run the build on device and tap on the shutter button, I can visually see it being tapped (fade out/in) but the code in shutterTapped() never executes.


Solution

  • Why is it not really working?

    Adding view of the view controller removes controller itself and no one can actually get the event. So, you get the view but not events. and to support this:

    enter image description here

    Solution that will actually work with your code would be:

    image.cameraOverlayView = overlay?.view
    if let viewController  = overlay {
    
        for view in viewController.view.subviews {
            if let button = view as? UIButton {
               button.addTarget(self, action: #selector(self.takePicture), for: UIControlEvents.touchDown)
            }
        }
    }
    

    You can also add tag to it so you can check which button is which if you have more of them.

    Alternate Solution:

    Create UIView subclass and xib for it. Same view you had in the OverlayVC. Then, when adding overlay use following:

    image.sourceType = .camera
    image.cameraDevice = .front
    image.allowsEditing = false
    let myOverlay = Bundle.main.loadNibNamed("CameraOverlay", owner: self, options: nil)
    image.cameraOverlayView = myOverlay?.first as! UIView
    image.showsCameraControls = false
    self.present(image, animated: true, completion: nil)
    

    Note that force unwrap should be protected with either guard or if let when casting to UIView.