Swift - Problems with corner radius and drop shadow
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 UIKitfinal 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 UIKitclass 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 }}
To expand on Imanou's post, it's possible to programmatically add the shadow layer in the custom button class
@IBDesignable class CustomButton: UIButton { var shadowAdded: Bool = false @IBInspectable var cornerRadius: CGFloat = 0 { didSet { layer.cornerRadius = cornerRadius layer.masksToBounds = cornerRadius > 0 } } override func drawRect(rect: CGRect) { super.drawRect(rect) if shadowAdded { return } shadowAdded = true let shadowLayer = UIView(frame: self.frame) shadowLayer.backgroundColor = UIColor.clearColor() shadowLayer.layer.shadowColor = UIColor.darkGrayColor().CGColor shadowLayer.layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: self.cornerRadius).CGPath shadowLayer.layer.shadowOffset = CGSize(width: 1.0, height: 1.0) shadowLayer.layer.shadowOpacity = 0.5 shadowLayer.layer.shadowRadius = 1 shadowLayer.layer.masksToBounds = true shadowLayer.clipsToBounds = false self.superview?.addSubview(shadowLayer) self.superview?.bringSubviewToFront(self) }}