1

Is it possible to have both CornerRaduis and a shadow on a UIView?

I set up a Custom class for a UIView which uses @IBInspectable to set a cornerRadius and a addShadow which can be true or false. When I set the cornerRadius the shadow doesn't display, if I take away the cornerRadius then it displays again. Thanks in advance!

Custom class:

import UIKit

class CustomUIView: UIView {

    override func awakeFromNib() {
        self.layer.masksToBounds = cornerRadius > 0
    }

    @IBInspectable var useDefaultRadius: Bool = true {
        didSet {
            self.layer.masksToBounds = cornerRadius > 0
        }
    }

    @IBInspectable var cornerRadius: CGFloat {
        set {
            self.layer.cornerRadius = newValue

        }
        get {
            if (useDefaultRadius) {
                    // Set default radius
                    self.layer.cornerRadius = 23
                }

            return self.layer.cornerRadius
        }
    }

    @IBInspectable var addShadow:Bool = true{

        didSet(newValue) {
            if(newValue == true){
                self.layer.masksToBounds = false
                self.layer.shadowColor = UIColor.black.cgColor
                self.layer.shadowOpacity = 0.5
                self.layer.shadowOffset = CGSize(width: 2, height: 3)
                self.layer.shadowRadius = 3

                self.layer.shadowPath = UIBezierPath(rect: bounds).cgPath
                self.layer.shouldRasterize = true
                self.layer.rasterizationScale =  UIScreen.main.scale
                print("trying to use shadow")
            }
        }

    }


}
Matthew Mitchell
  • 514
  • 4
  • 14

3 Answers3

11

Rather than creating custom clas and changing class of uiview everytime, i prefer extending it. I'm achieving this by extending UIView as mentioned below:

extension UIView {

    @IBInspectable
    var cornerRadius: CGFloat {
        get {
            return layer.cornerRadius
        }
        set {
            layer.cornerRadius = newValue
        }
    }

    @IBInspectable
    var borderWidth: CGFloat {
        get {
            return layer.borderWidth
        }
        set {
            layer.borderWidth = newValue
        }
    }

    @IBInspectable
    var borderColor: UIColor? {
        get {
            let color = UIColor.init(cgColor: layer.borderColor!)
            return color
        }
        set {
            layer.borderColor = newValue?.cgColor
        }
    }

    @IBInspectable
    var shadowRadius: CGFloat {
        get {
            return layer.shadowRadius
        }
        set {

            layer.shadowRadius = shadowRadius
        }
    }
    @IBInspectable
    var shadowOffset : CGSize{

        get{
            return layer.shadowOffset
        }set{

            layer.shadowOffset = newValue
        }
    }

    @IBInspectable
    var shadowColor : UIColor{
        get{
            return UIColor.init(cgColor: layer.shadowColor!)
        }
        set {
            layer.shadowColor = newValue.cgColor
        }
    }
    @IBInspectable
    var shadowOpacity : Float {

        get{
            return layer.shadowOpacity
        }
        set {

            layer.shadowOpacity = newValue

        }
    }        
}

And set properties in storyboard as:

enter image description here

That's it.

Hope this helps.

khush
  • 540
  • 5
  • 16
  • You sir are my savior – yuji Mar 15 '22 at 07:50
  • shadow color getter method will not return the correct color if the user change the iPhone from darkMode to lightMode (while the app running). OR let me say it will not call again so this answer need to be edit – Omarj Dec 13 '22 at 16:22
  • There's a bug. `shadowRadius`'s setter should be setting to `newValue` instead of itself. – Xavier L. May 14 '23 at 20:06
1

Set true masksToBounds in addShadow:Bool or you don't need to set masksToBounds in addShadow:Bool didSet method

@IBInspectable var addShadow:Bool = true{

        didSet(newValue) {
            if(newValue == true){
                //self.layer.masksToBounds = false
                self.layer.masksToBounds = true
                self.layer.shadowColor = UIColor.black.cgColor
                self.layer.shadowOpacity = 0.5
                self.layer.shadowOffset = CGSize(width: 2, height: 3)
                self.layer.shadowRadius = 3

                self.layer.shadowPath = UIBezierPath(rect: bounds).cgPath
                self.layer.shouldRasterize = true
                self.layer.rasterizationScale =  UIScreen.main.scale
                print("trying to use shadow")
            }
        }

    }

You can follow: https://medium.com/bytes-of-bits/swift-tips-adding-rounded-corners-and-shadows-to-a-uiview-691f67b83e4a

https://spin.atomicobject.com/2017/07/18/swift-interface-builder/

Jogendar Choudhary
  • 3,476
  • 1
  • 12
  • 26
  • @MatthewMitchell: you have added masksToBounds true for corner radios > 0 in awakeFromNib so remove this line then your code will also work – Jogendar Choudhary Mar 05 '19 at 09:49
  • Still not working, as soon as a I set a cornerRadius the shadow disappears – Matthew Mitchell Mar 05 '19 at 09:50
  • @MatthewMitchell I have updated answer. Can you try this one – Jogendar Choudhary Mar 05 '19 at 09:52
  • if i remove that, cornerRaduis stops working completely – Matthew Mitchell Mar 05 '19 at 09:53
  • @MatthewMitchell Ok then you need Set true masksToBounds in addShadow and follow the given link – Jogendar Choudhary Mar 05 '19 at 09:58
  • The problem here seems to be that the shadow is supposed to display outside the layer bounds, but since you have to set `masksToBounds=true` the shadow will be invisible (since it's outside the mask). You could create a view that uses a `CAShapeLayer` (`override static var layerClass: AnyClass { return CAShapeLayer.self }`}, and then set a rounded corner path (both as path and as shadowPath. You should then also override backgoundColor to get/set the shapeLayer's fillColor. – Lutz Mar 05 '19 at 10:08
  • @Lutz: have you follow my given links – Jogendar Choudhary Mar 05 '19 at 10:09
0

Here's the trick, you have to Set true to masksToBounds then Set false to masksToBounds before adding shadow code. you can check this method to make things clear:

func addShadow(color: UIColor, bottomOrTop: Bool = false, radius: CGFloat = 2, height: CGFloat = 3) {
        // These below line makes the trick to draw shadow with corner radius
        self.layer.masksToBounds = true
        self.layer.masksToBounds = false
        self.layer.shadowOffset = CGSize(width: height, height:  bottomOrTop ? height : height * -1)
        self.layer.shadowRadius = radius
        self.layer.shadowColor = color.cgColor
        self.layer.shadowOpacity = 0.3
    }
Michael Maher
  • 210
  • 4
  • 12