Estoy tratando de hacer un UIButton con esquinas redondeadas que tenga 2 sombras de colores. ¿Por qué está el rojo (y en este punto también la capa azul de "sombra" que cubre el botón? Cómo obtener las sombras debajo del lienzo del botón). Pensé que estaba ayudando a insertar subcapas en lugar de simplemente agregarlas.
He hecho un patio de recreo ilustrando el tema.
import UIKit import PlaygroundSupportEste es el botón que estoy tratando de implementar
class PrimaryButton: UIButton { required init(text: String = "Test 1", hasShadow: Bool = true) { super.init(frame: .zero) setTitle(text, for: .normal) backgroundColor = UIColor.blue layer.cornerRadius = 48 / 2 layer.masksToBounds = false if hasShadow { insertShadow() } } fileprivate func insertShadow() { let layer2 = CALayer(layer: layer), layer3 = CALayer(layer: layer) layer2.applySketchShadow(color: UIColor.red, alpha: 0.5, x: 0, y: 15, blur: 35, spread: -10) layer3.applySketchShadow(color: UIColor.blue, alpha: 0.5, x: 0, y: 10, blur: 21, spread: -9) layer.insertSublayer(layer2, at: 0) layer.insertSublayer(layer3, at: 0) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutSubviews() { super.layoutSubviews() layer.sublayers?.forEach { (sublayer) in sublayer.shadowPath = UIBezierPath(rect: bounds).cgPath } } }Esta es una extensión que ayuda a agregar la sombra de la especificación Sketch:
extension CALayer { func applySketchShadow( color: UIColor = .black, alpha: Float = 0.5, x: CGFloat = 0, y: CGFloat = 2, blur: CGFloat = 4, spread: CGFloat = 0) { shadowColor = color.cgColor shadowOpacity = alpha shadowOffset = CGSize(width: x, height: y) shadowRadius = blur / 2.0 if spread == 0 { shadowPath = nil } else { let dx = -spread let rect = bounds.insetBy(dx: dx, dy: dx) shadowPath = UIBezierPath(rect: rect).cgPath } masksToBounds = false } } class MyViewController : UIViewController { override func loadView() { let view = UIView() view.backgroundColor = .white let button = PrimaryButton() button.frame = CGRect(x: 150, y: 200, width: 200, height: 48) view.addSubview(button) self.view = view } } // Present the view controller in the Live View window PlaygroundPage.current.liveView = MyViewController()Me parece legítimo. layer1 y layer2 son subcapas de la capa del botón.
Podrías agregar una tercera capa que servirá como fondo. Aquí hay un ejemplo basado en su código:
class PrimaryButton: UIButton { let layer1 = CALayer(), layer2 = CALayer(), layer3 = CALayer() override func layoutSubviews() { super.layoutSubviews() layer1.backgroundColor = UIColor.blue.cgColor layer1.cornerRadius = 48 / 2 [layer1, layer2, layer3].forEach { $0.masksToBounds = false $0.frame = layer.bounds layer.insertSublayer($0, at: 0) } layer2.applySketchShadow(color: UIColor.red, alpha: 0.5, x: 0, y: 15, blur: 35, spread: -10) layer3.applySketchShadow(color: UIColor.blue, alpha: 0.5, x: 0, y: 10, blur: 21, spread: -9) } } Tenga en cuenta que puse la mayor parte del código dentro de layoutSubviews porque la mayoría de sus métodos usan los límites reales del botón.
Cambie sus inserciones a:
layer.insertSublayer(layer2, at: 1) layer.insertSublayer(layer3, at: 2)Deberias hacer eso.
Otra forma es agregar botones dobles sin cambiar su clase.
let button = PrimaryButton() button.frame = CGRect(x: 150, y: 200, width: 200, height: 48) button.backgroundColor = UIColor.clear view.addSubview(button) self.view = view let button1 = PrimaryButton() button1.frame = CGRect(x: 0, y: 0, width: 200, height: 48) button.addSubview(button1) button1.layer.sublayers?.forEach{$0.removeFromSuperlayer()}