使用Swift在UIView的draw()函数中绘制渐变。

7
我想在所有视图中添加渐变背景。我想到的方法是,创建一个新的 UIView 类,将 CAGradientLayer 的代码放入 draw() 方法中,以便在视图中绘制出来。这样,在界面构建器中,我只需要选择背景视图并将其类设置为我的自定义类即可。目前为止,它可以正常工作。
我的问题是:是否会出现问题?有人知道吗?因为从 UIView 继承的模型文件带有注释: //Only override draw() if you perform custom drawing.
我不知道是否需要创建一个层,或者 draw() 只适用于低级别的绘制之类的事情。对 draw() 函数的最佳用法一无所知。
下面是代码:
override func draw(_ rect: CGRect) {

        let layer = CAGradientLayer()
        layer.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)

        let color1 = UIColor(red: 4/255, green: 39/255, blue: 105/255, alpha: 1)
        let color2 = UIColor(red: 1/255, green: 91/255, blue: 168/255, alpha: 1)

        layer.colors = [color1.cgColor, color2.cgColor]
        self.layer.addSublayer(layer)
    }

你需要对渐变层使用位置属性。 - El Tomato
3个回答

13

您可以使用@IBDesignable@IBInspectable来从Storyboard配置startColor和endColor属性。如果想要在draw(_ rect:)方法中绘制,使用指定颜色和位置的CGGradient而不是CAGradientLayer。Simple Gradient类和draw(_ rect: CGRect)函数将如下所示。

import UIKit

@IBDesignable 
class GradientView: UIView {

    @IBInspectable var startColor: UIColor = UIColor(red: 4/255, green: 39/255, blue: 105/255, alpha: 1)
    @IBInspectable var endColor: UIColor = UIColor(red: 1/255, green: 91/255, blue: 168/255, alpha: 1)

    override func draw(_ rect: CGRect) {

      let context = UIGraphicsGetCurrentContext()!
      let colors = [startColor.cgColor, endColor.cgColor]

      let colorSpace = CGColorSpaceCreateDeviceRGB()

      let colorLocations: [CGFloat] = [0.0, 1.0]

      let gradient = CGGradient(colorsSpace: colorSpace,
                                     colors: colors as CFArray,
                                  locations: colorLocations)!

      let startPoint = CGPoint.zero
      let endPoint = CGPoint(x: 0, y: bounds.height)
      context.drawLinearGradient(gradient,
                          start: startPoint,
                            end: endPoint,
                        options: [CGGradientDrawingOptions(rawValue: 0)])
    }
}

您可以在这里教程中了解更多相关内容。


谢谢。我认为这就是我正在寻找的更接近的东西。而且运行得很好。 - Aisenhein
太好了,它有所帮助。现在你可以为不同的视图从Storyboard配置值了。 - Suhit Patil
2
@curiously77 更新了代码以修复崩溃。谢谢。 - Suhit Patil
1
@curiously77 不确定这是不是由于 Swift 5 的原因。在 drawLinearGradient 方法中,选项被声明为 OptionSetType 类型的枚举。因此,在这里传递 CGGradientDrawingOptions 枚举类型或包含枚举元素的集合。当我们不想应用任何选项时,可以指定空的 [ ]。请查看 https://stackoverflow.com/questions/36323615/cannot-convert-value-of-type-int-to-expected-argument-type-cggradientdrawingopti 这个问题以获取更多详细信息。 - Suhit Patil
1
另外,我也分享了教程和文档链接,请查看以防有任何疑问。请在 Playground 中尝试以上代码。 - Suhit Patil
显示剩余5条评论

1

draw函数中不应该添加CAGradientLayer。

如果您想要向视图添加渐变,最简单的方法是使用图层(就像您正在做的那样),但不是像这样...

您应该在init方法中将其添加到您的视图中,然后在layoutSubviews方法中更新其框架。

像这样:

class MyView: UIView {
    let gradientLayer: CAGradientLayer = {
        let l = CAGradientLayer()
        let color1 = UIColor(red: 4/255, green: 39/255, blue: 105/255, alpha: 1)
        let color2 = UIColor(red: 1/255, green: 91/255, blue: 168/255, alpha: 1)
        l.colors = [color1.cgColor, color2.cgColor]
        return l
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)

        layer.addSublayer(gradientLayer)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        gradientLayer.frame = bounds
    }
}

谢谢您的回答。但是使用这段代码后,渐变效果没有显示出来。我只看到了一个白色背景(视图本身的颜色)。 我需要在哪里调用init(frame)?我认为它从未被调用过。 Xcode要求我放置一个init(coder),我可以在其中调用init(frame)吗? - Aisenhein
如果您想支持IB/storyboards,则需要同时支持init(frame:)init(coder:) - 我通常有一个名为setup()的函数,由两个初始化程序调用。 - Jason Moore

1
我会创建UIView扩展并在需要时应用它。
extension UIView {
        func withGradienBackground(color1: UIColor, color2: UIColor, color3: UIColor, color4: UIColor) {
            let layerGradient = CAGradientLayer()

            layerGradient.colors = [color1.cgColor, color2.cgColor, color3.cgColor, color4.cgColor]
            layerGradient.frame = bounds
            layerGradient.startPoint = CGPoint(x: 1.5, y: 1.5)
            layerGradient.endPoint = CGPoint(x: 0.0, y: 0.0)
            layerGradient.locations = [0.0, 0.3, 0.4, 1.0]

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

在这里,您可以更改函数声明以指定startPointendPointlocations参数作为变量。
之后,只需像这样调用此方法。
gradienView.withGradienBackground(color1: UIColor.green, color2: UIColor.red, color3: UIColor.blue, color4: UIColor.white)

请注意,您可以在颜色数组中拥有任意数量的颜色。 P.S.

但是使用这个扩展,我需要在所有视图控制器中创建一个视图的出口来调用渐变函数。我想避免这种情况。无论如何,还是谢谢。 - Aisenhein

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