Search code examples
iosswiftuiviewcalayeruibezierpath

iOS: Shadow of subview covered by parent view


I have a view that has a subview. I would like the subview to have a shadow, not covered by the parent view. This works if the parent view is transparent, but if it's not part of the shadow is covered by it. I tried setting the zPosition of the subview and it didn't work.

Here's what it looks like:

enter image description here

And here's my code, which you can copy-paste into a Playground:

import UIKit
import PlaygroundSupport

import UIKit

class MyViewController : UIViewController {
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        let myView = MyView(frame: .init(x: 30,
                                         y: 30,
                                         width: 200,
                                         height: 200))

        view.addSubview(myView)
        self.view = view
    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

class MyView: UIView {
    let upper = UIView()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    private func commonInit() {
        upper.backgroundColor = .red
        upper.translatesAutoresizingMaskIntoConstraints = false
        addSubview(upper)
        
        NSLayoutConstraint.activate([
            upper.topAnchor.constraint(equalTo: topAnchor),
            upper.leadingAnchor.constraint(equalTo: leadingAnchor),
            upper.trailingAnchor.constraint(equalTo: trailingAnchor),
            upper.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.8)
        ])
        
        self.backgroundColor = .yellow
        
        layer.shadowColor = UIColor.blue.cgColor
        layer.shadowOpacity = 1
        layer.shadowOffset = .zero
        layer.shadowRadius = 5
        
        // desperate attempts
        upper.layer.zPosition = 1
        upper.layer.masksToBounds = false
        layer.masksToBounds = false
        bringSubviewToFront(upper)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        layer.shadowPath = UIBezierPath(rect: upper.frame).cgPath
    }
}


Solution

  • If you want subview to have shadow .. apply shadow to subview like this

        upper.layer.shadowColor = UIColor.blue.cgColor
        upper.layer.shadowOpacity = 1
        upper.layer.shadowOffset = .zero
        upper.layer.shadowRadius = 5
    

    From this code what you get is this

    enter image description here

    Let me know if i get it wrong and you need something else ... i will try to do that as well to help you out