【问题标题】:Drawing a gradient color in an arc with a rounded edge在圆角的圆弧中绘制渐变颜色
【发布时间】:2016-05-07 18:33:56
【问题描述】:

我想在 Swift 中复制它.. 进一步阅读:How to draw a linear gradient arc with Qt QPainter?

我已经知道如何在矩形视图内绘制渐变:

override func drawRect(rect: CGRect) {
        let currentContext = UIGraphicsGetCurrentContext()
        CGContextSaveGState(currentContext)
        let colorSpace = CGColorSpaceCreateDeviceRGB()

        let startColor = MyDisplay.displayColor(myMetric.currentValue)
        let startColorComponents = CGColorGetComponents(startColor.CGColor)
        let endColor = MyDisplay.gradientEndDisplayColor(myMetric.currentValue)
        let endColorComponents = CGColorGetComponents(endColor.CGColor)

        var colorComponents
            = [startColorComponents[0], startColorComponents[1], startColorComponents[2], startColorComponents[3], endColorComponents[0], endColorComponents[1], endColorComponents[2], endColorComponents[3]]

        var locations: [CGFloat] = [0.0, 1.0]
        let gradient = CGGradientCreateWithColorComponents(colorSpace, &colorComponents, &locations, 2)

        let startPoint = CGPointMake(0, 0)
        let endPoint = CGPointMake(1, 8)

        CGContextDrawLinearGradient(currentContext, gradient, startPoint, endPoint, CGGradientDrawingOptions.DrawsAfterEndLocation)
        CGContextRestoreGState(currentContext)
    }

以及如何画圆弧

func drawArc(color: UIColor, x: CGFloat, y: CGFloat, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, lineWidth: CGFloat, clockwise: Int32) {
        let context = UIGraphicsGetCurrentContext()
        CGContextSetLineWidth(context, lineWidth)
        CGContextSetStrokeColorWithColor(context,
                                         color.CGColor)
        CGContextAddArc(context, x, y, radius, startAngle, endAngle, clockwise)
        CGContextStrokePath(context)
    }

使用渐变,占据了整个视图。我不确定如何将渐变限制在特定区域,所以我创建了UIView 的子类,修改了框架并使用了渐变代码(第一个 sn-p)。

对于弧,我使用了第二个 sn-p。我在想我可以画一条弧线,然后在弧线的末端画一个圆,以圆润的弧度。我怎样才能做到这一点并在弧形上绘制渐变?

请忽略紫色标记。第一张图片是我指定的渐变弧的开始,第二张是渐变弧的结束,在开始弧的下方和左侧。

如何在 Swift 中使用 Core Graphics 进行绘制?

【问题讨论】:

    标签: swift core-graphics gradient


    【解决方案1】:
    override func draw(_ rect: CGRect) {
    
        //Add gradient layer
        let gl = CAGradientLayer()
        gl.frame = rect
        gl.colors = [UIColor.red.cgColor, UIColor.blue.cgColor]
        layer.addSublayer(gl)
    
        //create mask in the shape of arc
        let sl = CAShapeLayer()
        sl.frame = rect
        sl.lineWidth = 15.0
        sl.strokeColor = UIColor.red.cgColor
        let path = UIBezierPath()
        path.addArc(withCenter: .zero, radius: 250.0, startAngle: 10.0.radians, endAngle: 60.0.radians, clockwise: true)
        sl.fillColor = UIColor.clear.cgColor
        sl.lineCap = kCALineCapRound
        sl.path = path.cgPath
    
        //Add mask to gradient layer
        gl.mask = sl
    
    }
    

    希望这会有所帮助!

    【讨论】:

    • layer 是从哪里来的layer.addSublayer(gl)
    • UIView 有这个属性。 drawRect 方法在 UIView 内部。所以 layer 是 UIView 的一个属性,因此可以访问
    • 虽然完全正确,但请注意您现在可以使用实际的圆形渐变 - 请参阅答案
    【解决方案2】:

    2019 年的准确代码,具有真正的圆形渐变和完全灵活的末端位置:

    现在基本上你只需要一个渐变层和该层的蒙版。

    所以第一步,你需要一个“面具”

    iOS 中的“面具”到底是什么?

    在 iOS 中,您实际上使用 CAShapeLayer 来制作蒙版。

    这令人困惑。它应该被称为“CAShapeToUseAsAMaskLayer”之类的东西

    但这就是你的做法,一个 CAShapeLayer。

    第二步。在布局中,您必须调整形状图层的大小。就是这样。

    所以基本上就是这样:

    class SweetArc: UIView {
        
        open override func layoutSubviews() {
            super.layoutSubviews()
            arcLayer.frame = bounds
            gradientLayer.frame = bounds
        }
        
        private lazy var gradientLayer: CAGradientLayer = {
            let l = CAGradientLayer()
            ...
            l.mask = arcLayer
            layer.addSublayer(l)
            return l
        }()
        
        private lazy var arcLayer: CAShapeLayer = {
            let l = CAShapeLayer()
            ...
            return l
        }()
    }
    

    这就是全部。

    注意,渐变层的遮罩确实设置为形状层,我们将其命名为“arcLayer”。

    形状层用作遮罩。

    这是两层的确切代码:

    private lazy var gradientLayer: CAGradientLayer = {
        // recall that .conic is finally available in 12 !
        let l = CAGradientLayer()
        l.type = .conic
        l.colors = [
            UIColor.yellow,
            UIColor.red
            ].map{$0.cgColor}
        l.locations = [0,  1]
        l.startPoint = CGPoint(x: 0.5, y: 0.5)
        l.endPoint = CGPoint(x: 0.5, y: 0)
        l.mask = arcLayer
        layer.addSublayer(l)
        return l
    }()
    
    private lazy var arcLayer: CAShapeLayer = {
        let l = CAShapeLayer()
        l.path = arcPath
        
        // to use a shape layer as a mask, you mask with white-on-clear:
        l.fillColor = UIColor.clear.cgColor
        l.strokeColor = UIColor.white.cgColor
        
        l.lineWidth = lineThick
        l.lineCap = CAShapeLayerLineCap.round
        l.strokeStart = 0.4 // try values 0-1
        l.strokeEnd = 0.5 // try values 0-1
        return l
    }()
    

    再次注意,arcLayer 是您用作蒙版的形状图层 - 您实际上并未将其添加为子视图。

    请记住,用作蒙版的形状图层不会!被添加为子视图。

    这可能会造成混乱。它根本不是一个“层”。

    最后,注意 arcLayer 使用路径arcPath

    完美构建路径,以便 strokeStart 和 strokeEnd 正常工作。

    你想完美地构建路径。

    因此很容易设置笔画开始和笔画结束值。

    而且它们通过完美且正确地顺时针从顶部从 0 到 1 运行才有意义。

    这是具体的代码:

    private let lineThick: CGFloat = 10.0
    private let outerGap: CGFloat = 10.0
    private let beginFraction: CGFloat = 0  // 0 means from top; runs clockwise
    
    private lazy var arcPath: CGPath = {
        let b = beginFraction * .pi * 2.0
        return UIBezierPath(
            arcCenter: bounds.centerOfCGRect(),
            radius: bounds.width / 2.0 - lineThick / 2.0 - outerGap,
            startAngle: .pi * -0.5 + b,
            endAngle: .pi * 1.5 + b,
            clockwise: true
        ).cgPath
    }()
    

    你已经完成了!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-24
      • 1970-01-01
      • 2010-12-26
      • 1970-01-01
      • 2014-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多