Swift: 使用CALayers沿着贝塞尔路径创建渐变

12

我有一个相对简单的进度视图实现,使用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)

我现在想做的是将渐变添加到跟随(或弯曲)路径的进度环图层。我已经成功地向填充添加了线性渐变,但没有添加到路径中。

这是我想要的效果的示例:

enter image description here

到目前为止,我发现所有的方法都需要使用CoreGraphics和CGContext的一堆额外步骤,而这些步骤并不完全适合我的实现。任何帮助都将不胜感激,谢谢!


使用您的路径作为渐变图层的蒙版是否足够回答,或者您是否还希望您的渐变随着路径弯曲而不是显示为掩蔽线性渐变? - Ian MacDonald
我希望渐变能够弯曲到路径上。使用蒙版是我实现错误效果的其中一种方式。 - Kyle Begeman
你能画一张你想要的东西的图吗? - matt
@matt 更新了描述,并附上了我想要的效果的示例截图。 - Kyle Begeman
不,我明白他的问题,并不像简单的遮罩那样容易。他想要渐变沿着弧线走。当弧线再次向上填充时,它仍然是蓝色的,而不是变回紫色。 - Ian MacDonald
显示剩余3条评论
1个回答

7
我会先绘制一个渐变层,然后在其上面绘制一层黑色的弧形擦除层。以下是我根据您提供的图像大致尝试(我省略了中心的白色标签,但这很简单):

enter image description here

这是生成它的代码:

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)在代码中创建一个“角度”层。这个例子的重点只是展示如何“擦除”黑色层中的弧线,以揭示隐藏在其后面的渐变,并因此看起来像是用渐变进行绘画。

7
这并不完全符合原贴作者的要求。随着进度条填充接近100%,您的视图会显示它再次变得更紫色,而它应该在弧线的“结尾”继续保持更蓝色。 - Ian MacDonald
1
@IanMacDonald 在答案中添加了一个关于此事的段落。 - matt
1
有没有办法给圆形添加动画?我的意思是绘制弧线时加入动画效果。 - Reynaldo Aguilar
@matt:我怎样才能将背景颜色从黑色改为白色? - coreDeviOS

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