iosswiftuiimagepickercontrollercameraoverlayview

Positioning a UIImagePickerController cameraOverlayView on top of the camera preview


I want to add an overlay to my UIImagePickerController, but I only need it to cover the camera preview, and not the camera controls at the top or bottom. I cannot find anywhere a way to do this as the top/bottom controls heights are different on every device. I've seen it done before on other apps. Any guidance is appreciated.

imagePicker.sourceType = .camera
            
let overlay = UIView()
overlay.backgroundColor = UIColor(white: 1, alpha: 0.5)

imagePicker.cameraOverlayView!.addSubview(overlay)
// This is using a UIView extension to constrain my views. It's as simple as it looks.
overlay.anchor(top: imagePicker.cameraOverlayView!.topAnchor, left: imagePicker.cameraOverlayView!.leftAnchor, bottom: imagePicker.cameraOverlayView!.bottomAnchor, right: imagePicker.cameraOverlayView!.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 100, height: 100)
        
self.present(imagePicker, animated: true, completion: nil)

I want this translucent UIView to fill the red area only. I have no problem creating the frame to be 3:4 but it won't position correctly on the Y axis. imagePicker.cameraOverlayView!.centerYAnchor is the same as the device's centerYAnchor.

UIImagePickerController


Solution

  • Maybe not the best solution. Using view debugger you can inspect the view hierarchy. Now add the view into the child camera view port controller

    imagePicker = CustomPicker()
    imagePicker.sourceType = .camera
    present(imagePicker, animated: true, completion: nil)
    
    
    class CustomPicker: UIImagePickerController {
        let overlay = UIView()
        
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            if let camController = children.first?.children.first?.children.first, overlay.superview == nil {
                overlay.backgroundColor = UIColor(white: 1, alpha: 0.5)
                camController.view.addSubview(overlay)
                overlay.addPinConstraints(top: 0, left: 0, bottom: 0, right: 0)
            }
        }
    }
    
    extension UIView {
        func addPinConstraints(top: CGFloat? = nil, left: CGFloat? = nil, bottom: CGFloat? = nil, right: CGFloat? = nil) {
            guard let parent = superview else { return }
            translatesAutoresizingMaskIntoConstraints = false
            if let left = left {
                leadingAnchor.constraint(equalTo: parent.leadingAnchor, constant: left).isActive = true
            }
            if let right = right {
                trailingAnchor.constraint(equalTo: parent.trailingAnchor, constant: -right).isActive = true
            }
            if let top = top {
                topAnchor.constraint(equalTo: parent.topAnchor, constant: top).isActive = true
            }
            if let bottom = bottom {
                bottomAnchor.constraint(equalTo: parent.bottomAnchor, constant: -bottom).isActive = true
            }
        }
    }
    

    Screenshot of the view inspector, here child -> child -> child is the camera view port enter image description here