1
votes

UIButton avec image d'arrière-plan, coins arrondis et une ombre

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.

 entrez la description de l'image ici

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.

 entrez la description de l'image ici

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?

Projet de démonstration


0 commentaires

3 Réponses :


0
votes

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


0 commentaires

1
votes

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.


0 commentaires

1
votes

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
        }
    }
}

 entrez la description de l'image ici


6 commentaires

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.