The shape is filled in correctly to begin with but I can't figure out how to change the fill color or, even better, how to animate a fill color change on a UIBezierPath
. Just like changing the background color of a UIView is what I'm looking for.
var fillColor = UIColor()
func changeBackgroundColor() {
let animcolor = CABasicAnimation(keyPath: "fillColor")
animcolor.fromValue = UIColor.greenColor()
animcolor.toValue = UIColor.orangeColor()
animcolor.duration = 1.0;
animcolor.repeatCount = 0;
animcolor.autoreverses = true
shapeLayer.addAnimation(animcolor, forKey: "fillColor")
}
var fillColor = UIColor()
let clipPath = UIBezierPath()
let shapeLayer = CAShapeLayer()
override func drawRect(rect: CGRect) {
clipPath.moveToPoint(CGPointMake(self.bounds.minX + 7.65, self.bounds.minY - 0.25))
clipPath.addCurveToPoint(CGPointMake(self.bounds.minX + 7.65, self.bounds.minY + 36.1), controlPoint1: CGPointMake(self.bounds.minX - 2.38, self.bounds.minY + 9.79), controlPoint2: CGPointMake(self.bounds.minX - 2.38, self.bounds.minY + 26.06))
clipPath.addCurveToPoint(CGPointMake(self.bounds.minX + 43.99, self.bounds.minY + 36.1), controlPoint1: CGPointMake(self.bounds.minX + 17.69, self.bounds.minY + 46.13), controlPoint2: CGPointMake(self.bounds.minX + 33.96, self.bounds.minY + 46.13))
clipPath.addLineToPoint(CGPointMake(self.bounds.minX + 43.99, self.bounds.minY + 36.1))
clipPath.addLineToPoint(CGPointMake(self.bounds.minX + 44.01, self.bounds.minY + 0.19))
clipPath.addLineToPoint(CGPointMake(self.bounds.minX + 7.58, self.bounds.minY + 0.19))
clipPath.usesEvenOddFillRule = true
fillColor = userColor
}
clipPath.addClip()
fillColor.setFill()
clipPath.fill()
shapeLayer.path = clipPath.CGPath
self.layer.mask = shapeLayer
Just like changing the background color of a UIView is what I'm looking for.
But why can't you do exactly that? You're already masking the view to your path – so animating your background color would achieve the exact effect you want. Just get rid of the Core Graphics path filling – and also remove the drawRect
override, as you can't use drawRect
with an animation of the background.
If you really need to use drawRect
and animate the color, you could consider splitting up your UIView
into two UIViews
- one to draw the background layer (which you could animate), and one to draw the custom drawing. Alternatively, you could setup a CADisplayLink
to re-draw the view every frame with an intermediate background color – but that's not amazing in terms of performance.
As I say below, you can't animate the fill color of a UIBezierPath
directly. If you only want to change (instead of animate) the fill color with your existing code, then you'd just want to call setNeedsDisplay
with a different userColor
.
If you're asking this because you're using two different paths for the masking and filling, see my below (overcomplicated in hindsight) answer.
The problem is the fill color of a UIBezierPath
isn't animatable. But the fill color on a CAShapeLayer
is.
Therefore you want to use another CAShapeLayer
for the filling instead. I suggest you create a fillLayer
and a maskLayer
property in order to make their functions clear. Now because you're using a 100% layered approach, you can move your code out of the drawRect
, as you're no longer doing any Core Graphics drawing.
Also, it's worth noting that you need to use a CGColor
for the animation to and from values.
Something like this should do the trick:
var fillColor = UIColor.greenColor()
let maskLayer = CAShapeLayer()
let fillLayer = CAShapeLayer()
func changeBackgroundColor() {
let animcolor = CABasicAnimation(keyPath: "fillColor")
animcolor.fromValue = UIColor.greenColor().CGColor
animcolor.toValue = UIColor.orangeColor().CGColor
animcolor.duration = 1.0;
animcolor.repeatCount = 0;
animcolor.autoreverses = true
fillLayer.addAnimation(animcolor, forKey: "fillColor")
}
// re-adjust the clipping path when the view bounds changes
override func layoutSubviews() {
let clipPath = UIBezierPath()
clipPath.moveToPoint(CGPointMake(self.bounds.minX + 7.65, self.bounds.minY - 0.25))
clipPath.addCurveToPoint(CGPointMake(self.bounds.minX + 7.65, self.bounds.minY + 36.1), controlPoint1: CGPointMake(self.bounds.minX - 2.38, self.bounds.minY + 9.79), controlPoint2: CGPointMake(self.bounds.minX - 2.38, self.bounds.minY + 26.06))
clipPath.addCurveToPoint(CGPointMake(self.bounds.minX + 43.99, self.bounds.minY + 36.1), controlPoint1: CGPointMake(self.bounds.minX + 17.69, self.bounds.minY + 46.13), controlPoint2: CGPointMake(self.bounds.minX + 33.96, self.bounds.minY + 46.13))
clipPath.addLineToPoint(CGPointMake(self.bounds.minX + 43.99, self.bounds.minY + 36.1))
clipPath.addLineToPoint(CGPointMake(self.bounds.minX + 44.01, self.bounds.minY + 0.19))
clipPath.addLineToPoint(CGPointMake(self.bounds.minX + 7.58, self.bounds.minY + 0.19))
// update layer paths
fillLayer.path = clipPath.CGPath
maskLayer.path = clipPath.CGPath
}
override init(frame: CGRect) {
super.init(frame: frame)
// configure filling
fillLayer.fillColor = fillColor.CGColor
fillLayer.fillRule = kCAFillRuleEvenOdd
// add fill path to superlayer
layer.addSublayer(fillLayer)
// configure masking layer
maskLayer.fillRule = kCAFillRuleEvenOdd
layer.mask = maskLayer
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With