I'm trying to create a UIButton with rounded corners, a background image and a shadow. Before adding the shadow, everything works fine.
But after adding shadow values, the shadow doesn't show up. Obviously due to clipsToBounds
property value being set to true
. If I remove that, it looks like this.
Since I need the corner radius as well, I cannot have the clipsToBounds
be false
.
This is my code.
class CustomButton: UIButton {
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
clipsToBounds = true
}
}
var shadowRadius: CGFloat {
get {
return layer.shadowRadius
}
set {
layer.shadowRadius = newValue
}
}
var shadowOpacity: Float {
get {
return layer.shadowOpacity
}
set {
layer.shadowOpacity = newValue
}
}
var shadowOffset: CGSize {
get {
return layer.shadowOffset
}
set {
layer.shadowOffset = newValue
}
}
var shadowColor: UIColor? {
get {
if let color = layer.shadowColor {
return UIColor(cgColor: color)
}
return nil
}
set {
if let color = newValue {
layer.shadowColor = color.cgColor
} else {
layer.shadowColor = nil
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
private lazy var button: CustomButton = {
let button = CustomButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setBackgroundImage(UIImage(named: "Rectangle"), for: .normal)
button.setTitleColor(.white, for: .normal)
button.setTitle("Sign Up", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .semibold)
button.cornerRadius = 20
button.shadowColor = .systemGreen
button.shadowRadius = 10
button.shadowOpacity = 1
button.shadowOffset = CGSize(width: 0, height: 0)
return button
}()
Is there a workaround to have both the shadow and the corner radius?
You can do it via adding shadow and background image with different layer.
First, if you don't need the properties, remove all and modify your CustomButton
implementation just like below (modify as your need):
class CustomButton: UIButton {
private let cornerRadius: CGFloat = 20
private var imageLayer: CALayer!
private var shadowLayer: CALayer!
override func draw(_ rect: CGRect) {
addShadowsLayers(rect)
}
private func addShadowsLayers(_ rect: CGRect) {
// Add Image
if self.imageLayer == nil {
let imageLayer = CALayer()
imageLayer.frame = rect
imageLayer.contents = UIImage(named: "Rectangle")?.cgImage
imageLayer.cornerRadius = cornerRadius
imageLayer.masksToBounds = true
layer.insertSublayer(imageLayer, at: 0)
self.imageLayer = imageLayer
}
// Set the shadow
if self.shadowLayer == nil {
let shadowLayer = CALayer()
shadowLayer.masksToBounds = false
shadowLayer.shadowColor = UIColor.systemGreen.cgColor
shadowLayer.shadowOffset = .zero
shadowLayer.shadowOpacity = 1
shadowLayer.shadowRadius = 10
shadowLayer.shadowPath = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).cgPath
layer.insertSublayer(shadowLayer, at: 0)
self.shadowLayer = shadowLayer
}
}
}
And initialize your button like below:
private lazy var button: CustomButton = {
let button = CustomButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(.white, for: .normal)
button.setTitle("Sign Up", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .semibold)
return button
}()