Swift: UIView 的背景渐变色

16

我尝试为 UIView 添加渐变背景色遇到了困难。我创建了 UIView 的扩展,并添加了以下方法:

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

    layer.insertSublayer(gradientLayer, at: 0)
}

然后我打电话:

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

但是它不起作用。视图已经显示,但其背景完全透明。我也尝试使用 CGColor


2
请尝试访问以下链接:https://github.com/matvdg/Gradient-View - PPL
代码运行正常,请检查您的其余代码。 - Arash Etemad
7个回答

19

有两个问题:

  • 我需要设置起始点和结束点以提供渐变方向:

    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)
    }
    
  • 第二个问题是 CAGradientLayer 在视图布局后才生效。我通过在 viewDidAppear 中调用 setGradientBackground() 解决了这个问题:

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

8
为什么你实际上选择了自己的答案,而不是Moayad的答案?看起来他回答得更快。 - Zaporozhchenko Oleksandr
1
关于第二个问题:实际上是因为当调用viewDidAppear(_:)时,视图几何形状被设置了。你可以在其他地方调用setGradientBackground(colorTop:colorBottom:),比如viewDidLoad(),这样就不会添加多个渐变层。只需要确保在viewDidLayoutSubviews()中每次设置几何形状时更新渐变层的框架即可。 - David Steppenbeck

15

请将您的方法更新为以下代码:

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

12

Moayad的回答对我最有效,但顶部颜色与底部相反,所以我反转了他发布的函数。

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

6

对于@IBDesignable:您可以在Storyboard上自定义UI。 这样更易于使用。

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

你好,能否请您解释一下如何设置起始X、起始Y、结束X和结束Y???? - Rana Ali Waseem

3

这段代码运行良好。不过,你应该在layoutSubviews中调用它。

Swift 5

class ViewExample: UIView {

    // MARK: - Lifecycle
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

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

    override func layoutSubviews() {
        super.layoutSubviews()
        configureGradientLayer()
    }

    func configureGradientLayer(){
        backgroundColor = .clear
        let gradient = CAGradientLayer()
        gradient.colors = [UIColor.systemPurple.cgColor, UIColor.systemPink.cgColor]
        gradient.locations = [0, 1]
        gradient.frame = bounds
        layer.addSublayer(gradient)
    }

}


1
这对我的项目有效。
/**
 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
}

像这样调用
    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)

也许不够清晰的是 boundsOfGradient:边界将被设置为渐变的框架。简单地说,这将声明渐变的大小。

1

gmoraleda的回答是正确的。如果您正在使用AutoLayout,请在viewDidLayoutSubviews上执行此操作。


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