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
}
Swift 4 version, you can check code in playground
var fillColor = UIColor.green let maskLayer = CAShapeLayer() let fillLayer = CAShapeLayer() func changeBackgroundColor() { let animcolor = CABasicAnimation(keyPath: "fillColor") animcolor.fromValue = UIColor.green.cgColor animcolor.toValue = UIColor.orange.cgColor animcolor.duration = 1.0; animcolor.repeatCount = 0; animcolor.autoreverses = true fillLayer.add(animcolor, forKey: "fillColor") } // re-adjust the clipping path when the view bounds changes let view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300)) view.backgroundColor = UIColor.white func createPaths() { let clipPath = UIBezierPath() clipPath.move(to: CGPoint(x: view.bounds.minX + 7.65, y: view.bounds.minY - 0.25)) clipPath.addCurve(to: CGPoint(x: view.bounds.minX + 7.65, y: view.bounds.minY + 36.1), controlPoint1: CGPoint(x: view.bounds.minX - 2.38, y: view.bounds.minY + 9.79), controlPoint2: CGPoint(x: view.bounds.minX - 2.38, y: view.bounds.minY + 26.06)) clipPath.addCurve(to: CGPoint(x: view.bounds.minX + 43.99, y: view.bounds.minY + 36.1), controlPoint1: CGPoint(x: view.bounds.minX + 17.69, y: view.bounds.minY + 46.13), controlPoint2: CGPoint(x: view.bounds.minX + 33.96, y: view.bounds.minY + 46.13)) clipPath.addLine(to: CGPoint(x: view.bounds.minX + 43.99, y: view.bounds.minY + 36.1)) clipPath.addLine(to: CGPoint(x: view.bounds.minX + 44.01, y: view.bounds.minY + 0.19)) clipPath.addLine(to: CGPoint(x: view.bounds.minX + 7.58, y: view.bounds.minY + 0.19)) // update layer paths fillLayer.path = clipPath.cgPath maskLayer.path = clipPath.cgPath fillLayer.fillColor = fillColor.cgColor fillLayer.fillRule = .evenOdd view.layer.addSublayer(fillLayer) maskLayer.fillRule = .evenOdd view.layer.mask = maskLayer } createPaths()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.