web-dev-qa-db-fra.com

Swift: Dégradé d'arrière-plan pour UIView

J'ai du mal à ajouter un fond dégradé à UIView. J'ai fait un extension de UIView et j'ai ajouté la méthode suivante:

func setGradientBackground(colorTop: UIColor, colorBottom: UIColor) {
    let gradientLayer = CAGradientLayer()
    gradientLayer.colors = [colorTop, colorBottom]
    gradientLayer.frame = bounds

    layer.insertSublayer(gradientLayer, at: 0)
}

Ensuite j'appelle:

separatorView.setGradientBackground(colorTop: .clear, colorBottom: .red)

Mais ça ne marche pas. La vue est présentée mais son arrière-plan est parfaitement net. J'ai aussi essayé avec CGColor

7
gmoraleda

Il y avait 2 problèmes:

  • Je devais définir les points de début et de fin pour fournir une direction de dégradé:

    func setGradientBackground(colorTop: UIColor, colorBottom: UIColor) {
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [colorBottom.cgColor, colorTop.cgColor]
        gradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
        gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
        gradientLayer.locations = [0, 1]
        gradientLayer.frame = bounds
    
       layer.insertSublayer(gradientLayer, at: 0)
    }
    
  • Et le deuxième problème était que CAGradientLayer prend effet après la présentation de la vue. J'ai résolu que l'appel de setGradientBackground() sur viewDidAppear:

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        separatorView.setGradientBackground(colorTop: .clear, colorBottom: Colors.darkGrey)
    }
    
9
gmoraleda

La réponse de Moayad a fonctionné le mieux pour moi, mais c'était à l'envers avec la couleur du haut comme bas, j'ai donc inversé la fonction qu'il a publiée.

Swift 4

    func setGradientBackground(colorTop: UIColor, colorBottom: UIColor){
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [colorBottom.cgColor, colorTop.cgColor]
        gradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
        gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
        gradientLayer.locations = [0, 1]
        gradientLayer.frame = bounds

        layer.insertSublayer(gradientLayer, at: 0)
}
5
Andrew S

Mettez à jour votre méthode au coup de code:

func setGradientBackground(colorTop: UIColor, colorBottom: UIColor){
    let gradientLayer = CAGradientLayer()
    gradientLayer.colors = [colorTop.cgColor, colorBottom.cgColor]
    gradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
    gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
    gradientLayer.locations = [NSNumber(floatLiteral: 0.0), NSNumber(floatLiteral: 1.0)]
    gradientLayer.frame = self.bounds

    self.layer.insertSublayer(gradientLayer, at: 0)
}
5
Moayad Al kouz

Pour @IBDesignable: vous pouvez personnaliser votre interface utilisateur sur le storyboard. Il est plus simple à utiliser.

@IBDesignable class GradientView: UIView {

    @IBInspectable var startColor: UIColor = .blue {
        didSet {
            setNeedsLayout()
        }
    }

    @IBInspectable var endColor: UIColor = .green {
        didSet {
            setNeedsLayout()
        }
    }

    @IBInspectable var shadowColor: UIColor = .yellow {
        didSet {
            setNeedsLayout()
        }
    }

    @IBInspectable var shadowX: CGFloat = 0 {
        didSet {
            setNeedsLayout()
        }
    }

    @IBInspectable var shadowY: CGFloat = -3 {
        didSet {
            setNeedsLayout()
        }
    }

    @IBInspectable var shadowBlur: CGFloat = 3 {
        didSet {
            setNeedsLayout()
        }
    }

    @IBInspectable var startPointX: CGFloat = 0 {
        didSet {
            setNeedsLayout()
        }
    }

    @IBInspectable var startPointY: CGFloat = 0 {
        didSet {
            setNeedsLayout()
        }
    }

    @IBInspectable var endPointX: CGFloat = 0 {
        didSet {
            setNeedsLayout()
        }
    }

    @IBInspectable var endPointY: CGFloat = 0 {
        didSet {
            setNeedsLayout()
        }
    }

    @IBInspectable var cornerRadius: CGFloat = 0 {
        didSet {
            setNeedsLayout()
        }
    }

    override class var layerClass: AnyClass {
        return CAGradientLayer.self
    }

    override func layoutSubviews() {
        let gradientLayer = layer as! CAGradientLayer
        gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
        gradientLayer.startPoint = CGPoint(x: startPointX, y: startPointY)
        gradientLayer.endPoint = CGPoint(x: endPointX, y: endPointY)
        layer.cornerRadius = cornerRadius
        layer.shadowColor = shadowColor.cgColor
        layer.shadowOffset = CGSize(width: shadowX, height: shadowY)
        layer.shadowRadius = shadowBlur
        layer.shadowOpacity = 1
    }
}
2

la réponse de gmoraleda est correcte. Faites-le sur viewDidLayoutSubviews si vous utilisez AutoLayout.

1
George Alegre

Cela fonctionne pour mon projet

/**
 set a gradient to a view
 gradientColors must be cgColors
 gradientColors and locations must have the same array size
 example:
 let gradientColors = [UIColor.red.cgColor,UIColor.blue.cgColor,UIColor.yellow.cgColor]
 let locations:[NSNumber] = [0.0,0.8,1.0]
 */
static func setGradient(viewWithGradient: UIView, backgroundColor: UIColor, gradientColors: [CGColor], locations:[NSNumber], boundsOfGradient:CGRect) {

    if gradientColors.count != locations.count {
        print("gradientColors and locations must have same size!")
        return
    }

    viewWithGradient.backgroundColor = backgroundColor
    let mask = CAGradientLayer()
    mask.colors = gradientColors
    mask.locations = locations
    mask.frame = boundsOfGradient
    viewWithGradient.layer.mask = mask
}

Appel comme ça

    let gradientColors = [UIColor.red.cgColor,UIColor.blue.cgColor,UIColor.yellow.cgColor]
    let locations:[NSNumber] = [0.0,0.8,1.0]
    GeneralTools.setGradient(viewWithGradient: yourViewThatShouldGetGradient, backgroundColor: backgroundColorOfYourViewWithGradient, gradientColors: gradientColors, locations: locations, boundsOfGradient: viewWhereIsYourGradientInside.bounds)

Peut-être pas assez clair boundsOfGradient: Les limites seront définies sur votre cadre de dégradés. Donc, simplement dit, cela déclarera la taille de votre dégradé.

1
kuzdu