在Swift中设置按钮的背景渐变

46

我不知道如何在按钮上设置背景渐变(而不是将背景渐变设置为图像)。这与Android非常不同。

这是一个类,我必须定义一个可返回的渐变方案:

import UIKit

extension CAGradientLayer {

    func backgroundGradientColor() -> CAGradientLayer {
        let topColor = UIColor(red: (0/255.0), green: (153/255.0), blue:(51/255.0), alpha: 1)
        let bottomColor = UIColor(red: (0/255.0), green: (153/255.0), blue:(255/255.0), alpha: 1)

        let gradientColors: [CGColor] = [topColor.CGColor, bottomColor.CGColor]
        let gradientLocations: [Float] = [0.0, 1.0]

        let gradientLayer: CAGradientLayer = CAGradientLayer()
        gradientLayer.colors = gradientColors
        gradientLayer.locations = gradientLocations

        return gradientLayer

    }
}

我可以使用以下代码来设置整个视图的背景:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let background = CAGradientLayer().backgroundGradientColor()
        background.frame = self.view.bounds
        self.view.layer.insertSublayer(background, atIndex: 0)
    }
    //...
}

但是我该如何访问按钮的视图并插入子层或类似的内容呢?


这里对OP的问题的简单回答是:你不能在视图控制器中完成这个操作 - 你只需要子类化视图。这只需要一两行代码。 - Fattie
15个回答

1
我已经修改了这个非常好的答案,通过添加颜色、半径和渐变方向的init参数来提高按钮的可重用性。
我还添加了updateGradientColors方法,如果您想在某个时候更改渐变颜色,它可能会很有用。
class GradientButton: UIButton {

    private let colors: [UIColor]
    private let cornerRadius: CGFloat
    private let startPoint: CGPoint
    private let endPoint: CGPoint

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    init(colors: [UIColor],
         cornerRadius: CGFloat = 10,
         startPoint: CGPoint = CGPoint(x: 0, y: 0.5),
         endPoint: CGPoint = CGPoint(x: 1, y: 0.5)) {
        self.colors = colors
        self.cornerRadius = cornerRadius
        self.startPoint = startPoint
        self.endPoint = endPoint
        super.init(frame: .zero)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        gradientLayer.frame = bounds
    }

    private lazy var gradientLayer: CAGradientLayer = {
        let gl = CAGradientLayer()
        gl.frame = self.bounds
        gl.colors = colors.map { $0.cgColor }
        gl.startPoint = startPoint
        gl.endPoint = endPoint
        gl.cornerRadius = cornerRadius
        layer.insertSublayer(gl, at: 0)
        return gl
    }()

    func updateGradientColors(_ colors: [UIColor]) {
        gradientLayer.colors = colors.map { $0.cgColor }
    }
}

0
class GradientButton: UIButton {

    var gradientLayer: CAGradientLayer? {
        didSet {
            layer.sublayers?.filter { $0 is CAGradientLayer }.forEach { $0.removeFromSuperlayer() }

            if let gradientLayer = gradientLayer {
                layer.insertSublayer(gradientLayer, at: 0)
            }
        }
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        gradientLayer?.frame = self.bounds
    }
}

0

enter image description here

   class ButtonGradient : UIButton {
        override func layoutSubviews() {

            let layer : CAGradientLayer = CAGradientLayer()
            layer.frame.size = self.frame.size
            layer.frame.origin = CGPoint(x: 0, y: 0)

            //   layer.cornerRadius = CGFloat(frame.width / 20)
            let color0 = UIColor(red:255/255, green:122/255, blue:0/255, alpha:1.0).cgColor
            let color1 = UIColor(red:255/255, green:176/255, blue: 0/255, alpha:1.0).cgColor
            let color2 = UIColor(red:250/255, green:98/255, blue: 44/255, alpha:1.0).cgColor
            layer.locations = [0.5, 1.0]
            layer.startPoint = CGPoint(x: 0.0, y: 0.5)
            layer.endPoint = CGPoint(x: 0.5, y: 0.5)
            layer.colors = [color2,color0,color1]

            self.layer.insertSublayer(layer, at: 0)
        }
    }

然后在Storyboard中直接将“ButtonGredient”类分配给特定的按钮。


1
这是极其不正确的。你正在创建数百甚至数千个渐变层 - 每次布局应用程序时都会创建一个新的! - Fattie
1
是的。在插入子层之前,请添加以下行以删除现有的gradientLayer。 layer.name = "gradientLayer" self.layer.sublayers.filter {$0.name == layer.name }.first?.removeFromSuperLayer() - P C

0

在这里,我已经取了一个UIView并在其中添加了按钮。

     @IBOutlet weak var btnCenter: UIButton!
     @IBOutlet weak var viewCenter: UIView!

    // Create a gradient layer
    let gradient = CAGradientLayer()

    // gradient colors in order which they will visually appear
    gradient.colors = [UIColor.yello.cgColor, UIColor.blue.cgColor]

    // Gradient from left to right
    gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
    gradient.endPoint = CGPoint(x: 1.0, y: 0.5)

    // set the gradient layer to the same size as the view
    gradient.frame = viewCenter.bounds

    // add the gradient layer to the views layer for rendering
    viewCenter.layer.insertSublayer(gradient, at: 0)

    // Tha magic! Set the button as the views mask
    viewCenter.mask = btnCenter

    //Set corner Radius and border Width of button
    btnCenter.layer.cornerRadius =  btnCenter.frame.size.height / 2
    btnCenter.layer.borderWidth = 5.0

enter image description here


1
很不幸,这是完全错误的。在iOS工程领域,当您添加一个图层时,必须在 layoutSubviews 方法中进行形状调整(实际上这正是 layoutSubviews 存在的原因)。 - Fattie
是的。在插入子层之前,请添加以下行以删除现有的gradientLayer。 layer.name =“gradientLayer” self.layer.sublayers.filter {$ 0.name == layer.name} .first?.removeFromSuperLayer() - P C

0

有方法可以在不创建子层的情况下处理初始层。

import UIKit
@IBDesignable class GradientButton: UIButton {
    @IBInspectable var startColor: UIColor = UIColor.white
    @IBInspectable var endColor: UIColor = UIColor.white
    @IBInspectable var cornerRadius = CGFloat(5.0)

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

    override func layoutSubviews() {
        super.layoutSubviews()
        //This is an advanced gradient we do not use for now
//        (layer as! CAGradientLayer).startPoint = CGPoint(x: 0, y: 0)
//        (layer as! CAGradientLayer).endPoint = CGPoint(x: 1, y: 1)
//        (layer as! CAGradientLayer).locations = [0,1]

        // Simple gradient
        (layer as! CAGradientLayer).colors = [startColor.cgColor, endColor.cgColor]
        layer.cornerRadius = cornerRadius
    } 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接