2016-04-10 12 views
3

Die Form ist zu Beginn korrekt ausgefüllt, aber ich kann nicht herausfinden, wie man die Füllfarbe ändert oder, noch besser, wie man eine Füllfarbenänderung an einem UIBezierPath animiert. Genauso wie ich die Hintergrundfarbe einer UIView ändere.Wie animiert man eine Füllfarbenänderung auf UIBezierPath?

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 

Antwort

0

Genau wie die Änderung der Hintergrundfarbe eines UIView ist das, was ich suche.

Aber warum können Sie nicht genau das tun? Sie maskieren die Ansicht bereits auf Ihren Pfad. Wenn Sie also Ihre Hintergrundfarbe animieren, erzielen Sie genau den gewünschten Effekt. Befreien Sie sich einfach vom Core Graphics Pfad - und entfernen Sie auch den drawRect Override, wie Sie can't use drawRect with an animation of the background.

Wenn Sie wirklich Notwendigkeit drawRect und animieren die Farbe zu verwenden, Sie Splitting betrachten könnte Ihre UIView in zwei UIViews - man die Hintergrundebene zu ziehen (die Sie animieren könnte), und man die benutzerdefinierte Zeichnung zu zeichnen. Alternativ können Sie eine CADisplayLink einrichten, um die Ansicht jedes Frame mit einer Zwischenhintergrundfarbe neu zu zeichnen - aber das ist nicht erstaunlich in Bezug auf die Leistung.

Wie ich unten sage, können Sie nicht direkt die Füllfarbe eines UIBezierPath animieren. Wenn Sie nur die Füllfarbe mit dem vorhandenen Code ändern (statt animieren) möchten, können Sie einfach setNeedsDisplay mit einer anderen userColor aufrufen.

Wenn Sie dies fragen, weil Sie zwei verschiedene Pfade für das Maskieren und Füllen verwenden, finden Sie in meiner unten (im Nachhinein sehr kompliziert) Antwort.


Das Problem ist, die Füllfarbe eines UIBezierPath nicht animierbar ist. Aber die Füllfarbe auf einem CAShapeLayerist.

Daher möchten Sie stattdessen eine andere CAShapeLayer für die Füllung verwenden. Ich schlage vor, Sie erstellen eine fillLayer und eine maskLayer Eigenschaft, um ihre Funktionen klar zu machen. Jetzt, da Sie einen 100% -Schichtansatz verwenden, können Sie Ihren Code aus drawRect verschieben, da Sie keine Core Graphics-Zeichnung mehr machen.

Auch, es ist erwähnenswert, dass Sie eine CGColor für die Animation zu und von Werten verwenden müssen.

So etwas sollte es tun:

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 
} 
+0

Das ist genial. Danke, dass Sie das zu einer besseren Umsetzung beigetragen haben. Allerdings kann ich die Füllfarbe von 'fillLayer' nicht animieren, ich kann es nicht einmal ändern. Die Funktion wird definitiv aufgerufen, ich logge sie ein, um sicherzugehen. Dies ist die Art von Sache, wo ich mich hinsetze und denke, dass ich es in 30-40 Minuten auskurbeln werde und es dauert den halben Tag. –

+0

@spacemonkey Wird der 'fillLayer' vor dem Animieren auf dem Bildschirm angezeigt? Stellen Sie sicher, dass "frame" nicht null ist und dass es der Ebenenhierarchie hinzugefügt wird. Wenn Sie meinen obigen Code verwenden, müssen Sie die 'UIView' mit dem' init (frame:) 'Initialisierer initialisieren (in der Realität würden Sie Code mit beliebiger Größe an einen geeigneteren Ort wie' 'verschieben layoutSubviews' zum Beispiel). – Hamish

+0

Oh, es ist da. Genau wo und wie groß es sein sollte. Die Füllfarbe wird auf das eingestellt, was sie auch sein soll, sie wird einfach nicht zu etwas anderem wechseln. –

0

Swift-4-Version, können Sie Code in Spielplatz überprüfen

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 = kCAFillRuleEvenOdd 
 
    view.layer.addSublayer(fillLayer) 
 
    maskLayer.fillRule = kCAFillRuleEvenOdd 
 
    view.layer.mask = maskLayer 
 
} 
 

 
createPaths()

Verwandte Themen