So I have a bar chart where each bar is a CALayer. I want to animate each layer with a different delay.

private func drawBar(xPos: CGFloat, yPos: CGFloat, color: UIColor) {
    // create animation
    let animation = CABasicAnimation(keyPath: "bounds.size.height")
    animation.beginTime = CACurrentMediaTime() + StaticVars.delay
    animation.fromValue = 0
    animation.toValue = mainLayer.frame.height - bottomSpace - yPos
    animation.duration = 2.0
    StaticVars.delay += 0.1

    // create bar
    let barLayer = CALayer()
    barLayer.anchorPoint = CGPoint(x: 1, y: 1)
    barLayer.frame = CGRect(x: xPos, y: yPos, width: barWidth, height: mainLayer.frame.height - bottomSpace - yPos)
    barLayer.backgroundColor = color.cgColor
    barLayer.add(animation, forKey: nil)

This works well, but there is one issue: the chart is already present on the screen, than it waits for the delay (0.1) than it starts animating each layer with a delay.

I can't understand why the chart is already showing. What I want is when the app appears on the screen the bars should not be visible, just after the first delay should the chart start animating.

1 Answers

David Rönnqvist On Best Solutions

If you want the layer to appear to have the fromValue for the time before it begins (as set using the beginTime) you can configure it to fill "backwards" by setting the fillMode to .backwards:

animation.fillMode = .backwards

Without this, the animation will display the model value (the height of the actual frame of the layer) for all times before the beginTime and after beginTime + duration:

enter image description here

With this change, the animation will fill any value before the begin time with the fromValue (by clamping any time before the begin time to the start of the animation):

enter image description here