Cydiaddict
Cydiaddict

Reputation: 277

Apply a shadow on a UIView that have same corner radius than view

Hello i have some views with rounded corners, and I'd like to apply a shadow to this views.

SO first I round the view :

view.layer.cornerRadius = 15
view.clipsToBounds = true

then I apply the shadow :

    func dropShadow(scale: Bool = true) {
        self.layer.masksToBounds = false
        self.layer.cornerRadius = 15
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.layer.cornerRadius).cgPath
        self.layer.shadowOffset = CGSize(width: 3, height: 3)
        self.layer.shadowOpacity = 0.5
        self.layer.shadowRadius = 5
    }
view.dropShadow()

I got my rounded view with a shadow but the shadow is not rounded like my view. The shadow is not rounded at all

Upvotes: 0

Views: 5762

Answers (2)

matt
matt

Reputation: 534950

You cannot cast a shadow from a view whose clipsToBounds is true. If a view's masksToBounds is true, its clipsToBounds is true; they are the same thing.

If you want a shadow to appear to come from from a view that clips, you need to use two views: one that the user can see, with rounded corners and clipsToBounds set to true, and another that the user can't see because it's behind the first one, also with rounded corners, but with clipsToBounds set to false, to cast the shadow.

enter image description here

class ShadowView : UIView {
    override init(frame: CGRect) {
        super.init(frame:frame)
        self.isOpaque = true
        self.backgroundColor = .black
        self.dropShadow()
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    func dropShadow() {
        self.layer.masksToBounds = false
        self.layer.cornerRadius = 15
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowOffset = CGSize(width: 3, height: 3)
        self.layer.shadowOpacity = 0.5
        self.layer.shadowRadius = 5
    }
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let r = CGRect(x: 100, y: 100, width: 100, height: 100)
        let v = UIImageView(frame:r)
        v.image = UIImage(named:"marsSurface.jpg")
        v.clipsToBounds = true
        v.backgroundColor = .red
        v.layer.cornerRadius = 15
        self.view.addSubview(ShadowView(frame:r))
        self.view.addSubview(v)
    }
}

Note that neither view is a subview of the other, nor do they have a superview that clips, as that would clip the shadow.

Upvotes: 3

chen
chen

Reputation: 1

Trying to have a single view handle both corner rounding and shadow logic is not recommended. The best way to create the effect you are looking for is to wrap your rounded view with another parent view that owns the shadow.

This can be best illustrated with a playground. Try this code out in a playground.

import UIKit
import PlaygroundSupport

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

    let shadowView = UIView()
    shadowView.frame = CGRect(x: 50, y: 200, width: 200, height: 100)
    shadowView.backgroundColor = nil
    shadowView.layer.shadowColor = UIColor.black.cgColor
    shadowView.layer.shadowOffset = CGSize(width: 0, height: 4.0)
    shadowView.layer.shadowRadius = 8.0
    shadowView.layer.shadowOpacity = 1

    let roundedView = UIView()
    roundedView.frame = shadowView.bounds
    roundedView.backgroundColor = .gray
    roundedView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner,.layerMaxXMinYCorner]
    roundedView.layer.cornerRadius = 10
    roundedView.layer.masksToBounds = true

    shadowView.addSubview(roundedView)
    view.addSubview(shadowView)

    view.backgroundColor = UIColor.white
    self.view = view
  }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

Don't forget to set the shadowPath property on your shadow view's layer in either viewWillLayoutSubviews or layoutSubviews. If this property is set to nil, UIKit has to perform off screen rendering to figure out how to draw the shadow rect.

Upvotes: 0

Related Questions