iosswiftuiviewshadowcornerradius

Shadow and Corner Radius at the same time doesn't show in swift


I have a CameraView which has two button 1.takePictureButton 2.recordVideoButton. I want to add corner radius and shadow in the CameraView. So I add a innerView and add it as subview of CameraView. In the innerView I set the buttons. Though it shows corner Radius but not shadow.

I tried this :

class CameraView: UIView, UIImagePickerControllerDelegate & UINavigationControllerDelegate {
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.translatesAutoresizingMaskIntoConstraints = false
        self.backgroundColor = .clear
        self.layer.cornerRadius = 0.08 * self.bounds.size.width
        self.layer.masksToBounds = true

        let innerView = UIView(frame: self.bounds)
        innerView.translatesAutoresizingMaskIntoConstraints = false
        innerView.backgroundColor = .clear

        self.addSubview(innerView)

        let shadowPath = UIBezierPath(rect: innerView.frame)
        innerView.layer.shadowColor = UIColor.black.cgColor
        innerView.layer.shadowOpacity = 0.5
        innerView.layer.shadowOffset = CGSize(width: 0, height: 0)
        innerView.layer.shadowRadius = 5
        innerView.layer.shadowPath = shadowPath.cgPath
        innerView.clipsToBounds = true

        let takePictureButton = UIButton(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height/2))
        takePictureButton.backgroundColor = .white
        takePictureButton.setTitle("Take Picture", for: .normal)
        takePictureButton.setTitleColor(.black, for: .normal)
        takePictureButton.addTarget(self, action: #selector(takePictureButtonTapped), for: .touchUpInside)

        innerView.addSubview(takePictureButton)

        let recordVideoButton = UIButton(frame: CGRect(x: 0, y: frame.size.height/2 + 1, width: frame.size.width, height: frame.size.height/2 - 1))
        recordVideoButton.backgroundColor = .white
        recordVideoButton.setTitle("Record Video", for: .normal)
        recordVideoButton.addTarget(self, action: #selector(recordVideoButtonTapped), for: .touchUpInside)
        innerView.addSubview(recordVideoButton)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

Solution

  • Add shadow to the parent view rather than child view and change the shadow path to rounded rectangular as following: UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).

    Full code:

    class CameraView: UIView, UIImagePickerControllerDelegate & UINavigationControllerDelegate {
        override init(frame: CGRect) {
            super.init(frame: frame)
    
            let cornerRadius = 0.08 * bounds.size.width
            translatesAutoresizingMaskIntoConstraints = false
            backgroundColor = .clear
            layer.cornerRadius = cornerRadius
    
            let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
            layer.shadowColor = UIColor.black.cgColor
            layer.shadowOpacity = 0.5
            layer.shadowOffset = CGSize(width: 0, height: 0)
            layer.shadowRadius = 5
            layer.shadowPath = shadowPath.cgPath
    
            let innerView = UIView(frame: bounds)
            innerView.clipsToBounds = true
            innerView.backgroundColor = .clear
            innerView.layer.cornerRadius = cornerRadius
    
            let takePictureButton = UIButton(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height/2))
            takePictureButton.backgroundColor = .green
            takePictureButton.setTitle("Take Picture", for: .normal)
            takePictureButton.setTitleColor(.black, for: .normal)
    
            let recordVideoButton = UIButton(frame: CGRect(x: 0, y: frame.size.height/2 + 1, width: frame.size.width, height: frame.size.height/2 - 1))
            recordVideoButton.backgroundColor = .systemTeal
            recordVideoButton.setTitle("Record Video", for: .normal)
    
            innerView.addSubview(takePictureButton)
            innerView.addSubview(recordVideoButton)
            addSubview(innerView)
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }
    }
    
    #Preview {
        let vc = UIViewController()
        let cameraView = CameraView(frame: CGRect(x: 100, y: 100, width: 200, height: 100))
    
        vc.view.addSubview(cameraView)
        return vc;
    }