Ich habe einen benutzerdefinierten CALayer, der radiale Farbverläufe zeichnet. Es funktioniert gut, außer während der Animation. Es scheint, dass jede Iteration von CABasicAnimation
eine neue Kopie der CALayer
Unterklasse mit leeren, Standardwerte für die Eigenschaften erzeugt: obenCABasicAnimation erstellt leere Standardwerte Kopie von CALayer
Im Screenshot sehen Sie, dass CABasicAnimation
eine neue Kopie der Ebene geschaffen und aktualisiert gradientOrigin
, aber keine der anderen Eigenschaften sind für die Fahrt gekommen.
Dies hat zur Folge, dass während der Animation nichts gerendert wird. Hier ist ein GIF:
Hier ist, was aussehen soll ist:
Hier ist die Animation Code:
let animation = CABasicAnimation(keyPath: "gradientOrigin")
animation.duration = 2
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
let newOrigin: CGPoint = CGPoint(x: 0, y: triangle.bounds.height/2)
animation.fromValue = NSValue(CGPoint: triangle.gradientLayer.gradientOrigin)
animation.toValue = NSValue(CGPoint: newOrigin)
triangle.gradientLayer.gradientOrigin = newOrigin
triangle.gradientLayer.addAnimation(animation, forKey: nil)
Hier ist der Brauch CALayer Code:
enum RadialGradientLayerProperties: String {
case gradientOrigin
case gradientRadius
case colors
case locations
}
class RadialGradientLayer: CALayer {
var gradientOrigin = CGPoint() {
didSet { setNeedsDisplay() }
}
var gradientRadius = CGFloat() {
didSet { setNeedsDisplay() }
}
var colors = [CGColor]() {
didSet { setNeedsDisplay() }
}
var locations = [CGFloat]() {
didSet { setNeedsDisplay() }
}
override init(){
super.init()
needsDisplayOnBoundsChange = true
}
required init(coder aDecoder: NSCoder) {
super.init()
}
override init(layer: AnyObject) {
super.init(layer: layer)
}
override class func needsDisplayForKey(key: String) -> Bool {
if key == RadialGradientLayerProperties.gradientOrigin.rawValue || key == RadialGradientLayerProperties.gradientRadius.rawValue || key == RadialGradientLayerProperties.colors.rawValue || key == RadialGradientLayerProperties.locations.rawValue {
print("called \(key)")
return true
}
return super.needsDisplayForKey(key)
}
override func actionForKey(event: String) -> CAAction? {
if event == RadialGradientLayerProperties.gradientOrigin.rawValue || event == RadialGradientLayerProperties.gradientRadius.rawValue || event == RadialGradientLayerProperties.colors.rawValue || event == RadialGradientLayerProperties.locations.rawValue {
let animation = CABasicAnimation(keyPath: event)
animation.fromValue = self.presentationLayer()?.valueForKey(event)
return animation
}
return super.actionForKey(event)
}
override func drawInContext(ctx: CGContext) {
guard let colorRef = self.colors.first else { return }
let numberOfComponents = CGColorGetNumberOfComponents(colorRef)
let colorSpace = CGColorGetColorSpace(colorRef)
let deepGradientComponents: [[CGFloat]] = (self.colors.map {
let colorComponents = CGColorGetComponents($0)
let buffer = UnsafeBufferPointer(start: colorComponents, count: numberOfComponents)
return Array(buffer) as [CGFloat]
})
let flattenedGradientComponents = deepGradientComponents.flatMap({ $0 })
let gradient = CGGradientCreateWithColorComponents(colorSpace, flattenedGradientComponents, self.locations, self.locations.count)
CGContextDrawRadialGradient(ctx, gradient, self.gradientOrigin, 0, self.gradientOrigin, self.gradientRadius, .DrawsAfterEndLocation)
}
}
Aus der Dokumentation: „Das initializer wird verwendet, Schattenkopien von Schichten zu erzeugen, zum Beispiel für die presentationLayer Methode Mit dieser Methode in jeder anderen Situation wird nicht definiertes Verhalten erzeugt Für.. Beispiel: Verwenden Sie diese Methode nicht, um eine neue Ebene mit dem Inhalt einer vorhandenen Ebene zu initialisieren.Wenn Sie eine benutzerdefinierte Ebenenunterklasse implementieren, können Sie diese Methode überschreiben und sie verwenden, um die Werte von Instanzvariablen in das neue Objekt zu kopieren Rufen Sie die Superklassenimplementierung auf. " – matt