J'essaye de créer un UIButton avec des coins arrondis, une image d'arrière-plan et une ombre. Avant d'ajouter l'ombre, tout fonctionne correctement.
Mais après avoir ajouté des valeurs d'ombre, l'ombre n'apparaît pas. De toute évidence, la valeur de la propriété clipsToBounds
est définie sur true
. Si je supprime cela, cela ressemble à ceci.
Comme j'ai également besoin du rayon d'angle, je ne peux pas avoir le clipsToBounds be false
.
Ceci est mon 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 }()
Y a-t-il une solution de contournement à avoir à la fois l'ombre et le rayon du coin?
3 Réponses :
Vous pouvez ajouter view.layer.masksToBounds = false
Cela désactivera le découpage pour le sous-calque
https://developer.apple.com/documentation/quartzcore/calayer / 1410896-maskstobounds
Vous devez utiliser deux vues distinctes pour l'ombre et l'image. Je ne trouve aucune solution pour définir l'image, l'ombre et le rayon d'angle en utilisant le même calque de bouton.
Arrondissez le rayon du coin du bouton (clipsToBounds = true) et définissez l'image dessus.
Prenez une vue d'ombre sous le bouton avec un rayon et un décalage d'ombre appropriés.
Vous pouvez le faire en ajoutant une image d'ombre et d'arrière-plan avec un calque différent.
Premièrement, si vous n'avez pas besoin des propriétés, supprimez tout et modifiez votre implémentation CustomButton
comme ci-dessous (modifier selon vos besoins):
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 }()
Et initialisez votre bouton comme ci-dessous:
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 } } }
Merci. C'est bien. Mais le fait est que si je supprime les propriétés, je finis par coder en dur les valeurs à l'intérieur de la classe de bouton elle-même. J'espère en faire une solution plus générique. Je peux donc définir les valeurs de l'image d'ombre / d'arrière-plan lors de l'initialisation du bouton.
Mise à jour: j'ai modifié votre code comme ceci en exposant les propriétés. Fonctionne toujours très bien. Cependant j'ai remarqué un petit problème avec l'ombre. Si je réduis le rayon de l'ombre, l'ombre n'a pas le même rayon de coin. Voir . Une idée pourquoi cela peut être? Ce problème existe également dans le code d'origine. J'ai également essayé d'ajouter la valeur cornerRadius
au shadowLayer
, mais cela n'a rien changé.
Avez-vous donné le même rayon pour les deux? J'ai fait une petite mise à jour pour cela. (btw je ne peux pas accéder au premier lien). vous pouvez modifier / étendre n'importe quelle partie du code selon vos besoins, je garde simplement la partie requise pour ce que j'ai fait.
S'il vous plait verifiez maintenant. lien . cornerRadius
et shadowRadius
sont différents, non? Puisque le rayon de l'ombre gère le rayon de flou de l'ombre, je l'ai réglé sur 2. C'est là que j'ai remarqué les bords carrés de l'ombre. Le rayon du coin est toujours défini sur 20. Aucun problème avec cela.
Oui vous avez raison, j'ai modifié la ligne shadowLayer.shadowPath
.
@omerfarukozturk comment ajouter une animation de presse dans votre classe CustomButton? s'il vous plaît aider. Merci.