CABasicAnimation creates empty default value copy of CALayer

谁说胖子不能爱 提交于 2020-01-03 00:58:46

问题


I have a custom CALayer that draws radial gradients. It works great except during animation. It seems that each iteration of CABasicAnimation creates a new copy of the CALayer subclass with empty, default values for the properties:

In the screenshot above, you see that CABasicAnimation has created a new copy of the layer and is updating gradientOrigin but none of the other properties have come along for the ride.

This has the result of not rendering anything during the animation. Here's a GIF:

Here's what is should look like:

Here's the 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)

Here's the custom 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)

  }
}

回答1:


Figured out the answer!

In init(layer:) you have to copy the property values to your class manually. Here's how that looks in action:

override init(layer: AnyObject) {
  if let layer = layer as? RadialGradientLayer {
    gradientOrigin = layer.gradientOrigin
    gradientRadius = layer.gradientRadius
    colors = layer.colors
    locations = layer.locations
  }
  super.init(layer: layer)
}


来源:https://stackoverflow.com/questions/38468515/cabasicanimation-creates-empty-default-value-copy-of-calayer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!