aryaxt aryaxt - 7 months ago 27
Swift Question

CoreAnimation and CAReplicatorLayer in Swift?

I'm porting this library from objc to Swift and I'm having problems finding out why the replicator layer instanceCount is not doing anything to the animation. Any thoughts?

If you look at the library it has multiple instances of the layer animating at the same time, but in my code, only a single layer animates at a time.

https://github.com/shu223/PulsingHalo/blob/master/PulsingHalo/PulsingHaloLayer.m

public class PulsingHaloLayer2: CAReplicatorLayer {

var fromValueForRadius: Float = 0.0
var fromValueForAlpha: Float = 0.45
var keyTimeForHalfOpacity: Float = 0.2
var animationDuration: NSTimeInterval = 3.0
var pulseInterval: NSTimeInterval = 0.0
var useTimingFunction: Bool = true
let animationGroup: CAAnimationGroup = CAAnimationGroup()
var repetitions: Float = Float.infinity
var radius: CGFloat = 200.0 {
didSet {
let tempPos = position
let diameter = radius * 2

bounds = CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter)
cornerRadius = radius
position = tempPos
}
}
var haloLayerNumber: Int = 4 {
didSet {
instanceCount = 4
instanceDelay = (animationDuration + pulseInterval) / Double(haloLayerNumber)
}
}

override init() {
super.init()
contentsScale = UIScreen.mainScreen().scale
opacity = 0.0
backgroundColor = UIColor.blueColor().CGColor
haloLayerNumber = 4

setupAnimationGroup()
addAnimation(animationGroup, forKey: "pulse")
}

required public init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func setupAnimationGroup() {
animationGroup.duration = animationDuration + pulseInterval
animationGroup.repeatCount = repetitions
animationGroup.removedOnCompletion = false

if useTimingFunction {
let defaultCurve = CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault)
animationGroup.timingFunction = defaultCurve
}

let opacityAnimation = CAKeyframeAnimation(keyPath: "opacity")
opacityAnimation.duration = animationDuration
opacityAnimation.values = [fromValueForAlpha, 0.45, 0]
opacityAnimation.keyTimes = [0, keyTimeForHalfOpacity, 1]

let scaleAnimation = CABasicAnimation(keyPath: "transform.scale.xy")
scaleAnimation.fromValue = fromValueForRadius
scaleAnimation.toValue = 1
scaleAnimation.duration = animationDuration

animationGroup.animations = [opacityAnimation, scaleAnimation]
}

}

Answer

When you call haloLayerNumber = 4, this does not trigger the didSet block, because it's happening inside of init.

You can work around this using a closure: ({ haloLayerNumber = 4 })(). Or you can manually update the instanceCount/instanceDelay from inside of init.

Comments