Swift:沿贝塞尔路径渐变(使用 CALayers)

Posted

技术标签:

【中文标题】Swift:沿贝塞尔路径渐变(使用 CALayers)【英文标题】:Swift: Gradient along a bezier path (using CALayers) 【发布时间】:2015-01-13 20:37:57 【问题描述】:

我有一个使用 CALayer 对象设置的进度视图的相对直接的实现。进度视图本身是 UIView 的子视图。

这是设置进度环的代码:

        self.progressRingLayer = CAShapeLayer()

        let innerRect = CGRectInset(bounds, CGFloat(self.lineWidth) / 2, CGFloat(self.lineWidth) / 2)
        let innerPath = UIBezierPath(ovalInRect: innerRect)

        self.progressRingLayer.path = innerPath.CGPath
        self.progressRingLayer.fillColor = UIColor.clearColor().CGColor
        self.progressRingLayer.strokeColor = kProgressColor.CGColor
        self.progressRingLayer.anchorPoint = CGPointMake(0.5, 0.5)
        self.progressRingLayer.transform = CATransform3DRotate(self.progressRingLayer.transform, (CGFloat(M_PI))*1, 0, 0, 1)
        self.progressRingLayer.lineCap = kCALineCapRound
        self.progressRingLayer.lineWidth = CGFloat(self.lineWidth)

        self.layer.addSublayer(self.progressRingLayer)

我现在要做的是向沿着(或弯曲)路径的 progressRingLayer 添加一个渐变。我已经成功地为填充添加了线性渐变,但不仅仅是路径。

这是我想要的效果示例:

到目前为止,我发现的所有内容都需要使用 CoreGraphics 和 CGContext 执行一系列额外步骤,这些步骤与我的实现不太相符。任何帮助都会很棒,谢谢!

【问题讨论】:

将您的路径用作渐变层的蒙版就足够了,或者您是否还希望您的渐变随着您的路径弯曲而不是显示为蒙版线性渐变? 我希望让渐变弯曲到路径。使用蒙版是我实现错误效果的方法之一。 你能画出你想要的东西吗? @matt 用我想要的效果的示例截图更新了描述。 嗯,正如@IanMacDonald 所建议的那样,这看起来确实像一个在视图后面显示渐变的蒙版。您可以预先准备渐变图像,也可以在代码中绘制它。然后,您只需“擦除”黑色绘图的弧线以使渐变显示出来。 【参考方案1】:

我要做的是绘制一个渐变层,然后在该层上绘制一个黑色并擦除弧线的层。

这是我对您提供的图像的大致尝试(我省略了中心的白色标签,但这很简单):

这是生成它的代码:

let r = CGRectMake(100,100,130,100)

let g = CAGradientLayer()
g.frame = r
let c1 = UIColor(
    red: 151.0/255.0, green: 81.0/255.0, blue: 227.0/255.0, alpha: 1)
let c2 = UIColor(
    red: 36.0/255.0, green: 176.0/255.0, blue: 233.0/255.0, alpha: 1)
g.colors = [c1.CGColor as AnyObject, c2.CGColor as AnyObject];
self.view.layer.addSublayer(g)

let percent = CGFloat(0.64) // percentage of circle
UIGraphicsBeginImageContextWithOptions(r.size, false, 0)
let con = UIGraphicsGetCurrentContext()
CGContextFillRect(con, CGRect(origin: CGPoint(), size: r.size))
CGContextSetLineWidth(con, 5)
CGContextSetLineCap(con, kCGLineCapRound)
CGContextSetBlendMode(con, kCGBlendModeClear)
let pi = CGFloat(M_PI)
CGContextAddArc(con, r.size.width/2.0, r.size.height/2.0, 30, 
    -pi/2.0, -pi/2.0 + percent*pi*2.0, 0)
CGContextStrokePath(con)
let im = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let b = CALayer()
b.frame = r
b.contents = im.CGImage
self.view.layer.addSublayer(b)

渐变层(代码的第一部分)只是一个“服务建议”。如果那不是您想要的渐变,您可以自己设计。您可以在 Photoshop 中绘制它并使用图像作为渐变层的内容。或者,您可以使用第三方代码(例如https://github.com/paiv/AngleGradientLayer)在代码中创建一个“角度”层。该示例的重点只是说明如何可以“擦除”黑色层中的弧线,以显示隐藏在其后面的渐变,从而看起来像是用渐变绘制的。

【讨论】:

这并不完全符合 OP 的要求。随着进度接近 100%,您的视图将显示它再次变得更紫色,而在弧线的“末端”它应该继续更蓝。 @IanMacDonald 在答案中添加了一段关于此的内容。 有没有办法给圆圈添加动画?我的意思是画圆弧动画 @matt : 如何将背景颜色从黑色更改为白色?

以上是关于Swift:沿贝塞尔路径渐变(使用 CALayers)的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 中沿路径填充颜色渐变

在 3d 中沿贝塞尔路径移动对象:旋转问题

每个 CALayer 都有自己的绘图上下文吗?

如何用渐变颜色的控制点填充贝塞尔路径

沿 SVG 路径绘制

iOS - 如何沿路径绘制渐变