I'm trying to create a button with rounded corners and a drop shadow. No matter how I switch up, the button will not display correctly. I've tried masksToBounds = false
and masksToBounds = true
, but either the corner radius works and the shadow does not or the shadow works and the corner radius doesn't clip the corners of the button.
import UIKit import QuartzCore @IBDesignable class Button : UIButton { @IBInspectable var masksToBounds: Bool = false {didSet{updateLayerProperties()}} @IBInspectable var cornerRadius : CGFloat = 0 {didSet{updateLayerProperties()}} @IBInspectable var borderWidth : CGFloat = 0 {didSet{updateLayerProperties()}} @IBInspectable var borderColor : UIColor = UIColor.clearColor() {didSet{updateLayerProperties()}} @IBInspectable var shadowColor : UIColor = UIColor.clearColor() {didSet{updateLayerProperties()}} @IBInspectable var shadowOpacity: CGFloat = 0 {didSet{updateLayerProperties()}} @IBInspectable var shadowRadius : CGFloat = 0 {didSet{updateLayerProperties()}} @IBInspectable var shadowOffset : CGSize = CGSizeMake(0, 0) {didSet{updateLayerProperties()}} override func drawRect(rect: CGRect) { updateLayerProperties() } func updateLayerProperties() { self.layer.masksToBounds = masksToBounds self.layer.cornerRadius = cornerRadius self.layer.borderWidth = borderWidth self.layer.borderColor = borderColor.CGColor self.layer.shadowColor = shadowColor.CGColor self.layer.shadowOpacity = CFloat(shadowOpacity) self.layer.shadowRadius = shadowRadius self.layer.shadowOffset = shadowOffset } }
Add subview with the same color which will be centered on the parent and will be with several pixels smaller. Like this you will have space from each side of the parent. On the parent turn on clipping subviews and add shadow to the inner view. Like this, you can have an inner shadow.
You can give it round corners by changing the cornerRadius property of the view's layer . and smaller values give less rounded corners. Both clipsToBounds and masksToBounds are equivalent.
Using CAShapeLayer and UIBezierPath we can easily add shadow and corner radius to UIView and the class derived from it like UIButton, UIImageView, UILabel etc. We will add UIView Extension and the good point of this is, you only need to write just one line of code to achieve this.
If you add something like a UIVisualEffectView as a subview to this view you likely need to use the same rounded corners on that UIVisualEffectView or it won't have rounded corners.
Implementing the @IBDesignable UIView extension and applying the @IBInspectable modifier to the cornerRadius property allows a view’s corner radius to be set in a Storyboard’s Attributes Inspector: Adding a shadow to a UIView can be implemented by setting the shadowColor, shadowOpacity, shadowOffset, and shadowRadius properties on the view’s layer:
Subclass your view from this and it should have rounded corners. If you add something like a UIVisualEffectView as a subview to this view you likely need to use the same rounded corners on that UIVisualEffectView or it won't have rounded corners.
The following Swift 5 / iOS 12 code shows how to set a subclass of UIButton
that allows to create instances with rounded corners and shadow around it:
import UIKit final class CustomButton: UIButton { private var shadowLayer: CAShapeLayer! override func layoutSubviews() { super.layoutSubviews() if shadowLayer == nil { shadowLayer = CAShapeLayer() shadowLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: 12).cgPath shadowLayer.fillColor = UIColor.white.cgColor shadowLayer.shadowColor = UIColor.darkGray.cgColor shadowLayer.shadowPath = shadowLayer.path shadowLayer.shadowOffset = CGSize(width: 2.0, height: 2.0) shadowLayer.shadowOpacity = 0.8 shadowLayer.shadowRadius = 2 layer.insertSublayer(shadowLayer, at: 0) //layer.insertSublayer(shadowLayer, below: nil) // also works } } }
According to your needs, you may add a UIButton
in your Storyboard and set its class to CustomButton
or you may create an instance of CustomButton
programmatically. The following UIViewController
implementation shows how to create and use a CustomButton
instance programmatically:
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let button = CustomButton(type: .system) button.setTitle("Button", for: .normal) view.addSubview(button) button.translatesAutoresizingMaskIntoConstraints = false let horizontalConstraint = button.centerXAnchor.constraint(equalTo: view.centerXAnchor) let verticalConstraint = button.centerYAnchor.constraint(equalTo: view.centerYAnchor) let widthConstraint = button.widthAnchor.constraint(equalToConstant: 100) let heightConstraint = button.heightAnchor.constraint(equalToConstant: 100) NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint]) } }
The previous code produces the image below in the iPhone simulator:
My custom button with some shadow and rounded corners, I use it directly within the Storyboard
with no need to touch it programmatically.
Swift 4
class RoundedButtonWithShadow: UIButton { override func awakeFromNib() { super.awakeFromNib() self.layer.masksToBounds = false self.layer.cornerRadius = self.frame.height/2 self.layer.shadowColor = UIColor.black.cgColor self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.layer.cornerRadius).cgPath self.layer.shadowOffset = CGSize(width: 0.0, height: 3.0) self.layer.shadowOpacity = 0.5 self.layer.shadowRadius = 1.0 } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With