如何使 CAGradientLayer 遵循 CGPath
How to make a CAGradientLayer follow a CGPath
给定如下图所示定义路径的 CAShapeLayer,我想添加一个遵循形状图层路径的 CAGradientLayer。
例如,给定从黑色到红色的渐变:
- 右上角的圆形部分为黑色,
- 如果滑块位于 100,则左上角将为红色,
- 如果滑块位于 50,则滑块的一半将为黑色(如下所示),并且可见渐变将从黑色(右上角)变为底部的红黑色
我发现的每个以前的 post 实际上都没有回答这个问题。
例如,因为我只能添加轴向 CAGradientLayers,所以我可以这样做(下图),但您可以看到它不正确(左上角最终再次变黑)。如何使渐变真正遵循 path/mask
对于简单的圆形路径,新的圆锥梯度很棒。我能够立即得到这个(这是一个被圆形图层掩盖的圆锥渐变图层):
我使用了红色和绿色,以便清楚地显示渐变。这似乎与您所追求的不尽相同,但我不敢相信现在 .conic
存在,实现您的目标会非常困难。
class MyGradientView : UIView {
override class var layerClass : AnyClass { return CAGradientLayer.self }
required init?(coder aDecoder: NSCoder) {
super.init(coder:aDecoder)
let lay = self.layer as! CAGradientLayer
lay.type = .conic
lay.startPoint = CGPoint(x:0.5,y:0.5)
lay.endPoint = CGPoint(x:0.5,y:0)
lay.colors = [UIColor.green.cgColor, UIColor.red.cgColor]
}
override func layoutSubviews() {
super.layoutSubviews()
let shape = CAShapeLayer()
shape.frame = self.bounds
shape.strokeColor = UIColor.black.cgColor
shape.fillColor = UIColor.clear.cgColor
let b = UIBezierPath(ovalIn: shape.frame.inset(by: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)))
shape.path = b.cgPath
shape.lineWidth = 10
shape.lineCap = .round
shape.strokeStart = 0.1
shape.strokeEnd = 0.9
shape.anchorPoint = CGPoint(x: 0.5, y: 0.5)
shape.transform = CATransform3DMakeRotation(-.pi/2, 0, 0, 1)
self.layer.mask = shape
}
}
iOS12 上的任何人都应该采纳 Matt 的建议,或者按照 DonMag 的建议使用 SFProgressCircle。
我的解决方案:
我个人最终添加了两个 CAShapeLayer,每个都有一个对应的 CAGradientLayer。
通过编程方式将滑块分成两半,如下图所示,我能够在每一侧应用从上到下的渐变,这提供了我正在寻找的效果。它对用户是不可见的。
给定如下图所示定义路径的 CAShapeLayer,我想添加一个遵循形状图层路径的 CAGradientLayer。
例如,给定从黑色到红色的渐变:
- 右上角的圆形部分为黑色,
- 如果滑块位于 100,则左上角将为红色,
- 如果滑块位于 50,则滑块的一半将为黑色(如下所示),并且可见渐变将从黑色(右上角)变为底部的红黑色
我发现的每个以前的 post 实际上都没有回答这个问题。 例如,因为我只能添加轴向 CAGradientLayers,所以我可以这样做(下图),但您可以看到它不正确(左上角最终再次变黑)。如何使渐变真正遵循 path/mask
对于简单的圆形路径,新的圆锥梯度很棒。我能够立即得到这个(这是一个被圆形图层掩盖的圆锥渐变图层):
我使用了红色和绿色,以便清楚地显示渐变。这似乎与您所追求的不尽相同,但我不敢相信现在 .conic
存在,实现您的目标会非常困难。
class MyGradientView : UIView {
override class var layerClass : AnyClass { return CAGradientLayer.self }
required init?(coder aDecoder: NSCoder) {
super.init(coder:aDecoder)
let lay = self.layer as! CAGradientLayer
lay.type = .conic
lay.startPoint = CGPoint(x:0.5,y:0.5)
lay.endPoint = CGPoint(x:0.5,y:0)
lay.colors = [UIColor.green.cgColor, UIColor.red.cgColor]
}
override func layoutSubviews() {
super.layoutSubviews()
let shape = CAShapeLayer()
shape.frame = self.bounds
shape.strokeColor = UIColor.black.cgColor
shape.fillColor = UIColor.clear.cgColor
let b = UIBezierPath(ovalIn: shape.frame.inset(by: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)))
shape.path = b.cgPath
shape.lineWidth = 10
shape.lineCap = .round
shape.strokeStart = 0.1
shape.strokeEnd = 0.9
shape.anchorPoint = CGPoint(x: 0.5, y: 0.5)
shape.transform = CATransform3DMakeRotation(-.pi/2, 0, 0, 1)
self.layer.mask = shape
}
}
iOS12 上的任何人都应该采纳 Matt 的建议,或者按照 DonMag 的建议使用 SFProgressCircle。
我的解决方案: 我个人最终添加了两个 CAShapeLayer,每个都有一个对应的 CAGradientLayer。
通过编程方式将滑块分成两半,如下图所示,我能够在每一侧应用从上到下的渐变,这提供了我正在寻找的效果。它对用户是不可见的。