Search code examples
iosobjective-cswiftcore-animationcagradientlayer

Gradient Animation - Slow down and speed up


I'm animating a CAGradientLayer, similar to how Apple did with their "Slide to Unlock" animation on the home screen of iPhone. However my animation is a little different in that it slows down and speeds up at certain points.

The code I have so far is animates a gradient and works, but how would I get it to slow down/speed up at different points?

class AnimatedMaskLabel: UIView {

    let gradientLayer: CAGradientLayer = {
    let gradientLayer = CAGradientLayer()
        // Configure the gradient here
        gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
        gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)

        let colors = [
            UIColor.black.cgColor,
            UIColor.white.cgColor,
            UIColor.black.cgColor
        ]
        gradientLayer.colors = colors

        let locations: [NSNumber] = [0.0, 0.5, 1.0]
        gradientLayer.locations = locations

        return gradientLayer
    }()

  @IBInspectable var text: String! {
    didSet {
      setNeedsDisplay()
    }
  }

  override func layoutSubviews() {
    layer.borderColor = UIColor.green.cgColor
    gradientLayer.frame = bounds
  }

  override func didMoveToWindow() {
    super.didMoveToWindow()

    layer.addSublayer(gradientLayer)

    let gradientAnimation = CABasicAnimation(keyPath: "locations")
    gradientAnimation.fromValue = [0.0, 0.0, 0.25]
    gradientAnimation.toValue = [0.75, 1.0, 1.0]
    gradientAnimation.duration = 3.0
    gradientAnimation.repeatCount = Float.infinity
    gradientLayer.add(gradientAnimation, forKey: nil)
  }

}

Update 1:

enter image description here

To make it look exactly like I want, would I need to use CAMediaTimingFunction at all?


Solution

  • To use a keyframe animation, try:

    let gradientAnimation = CAKeyframeAnimation(keyPath: "locations")
    gradientAnimation.values = [[0.0, 0.0, 0.25], [0.375, 0.5, 0.625], [0.75, 1.0, 1.0]]
    gradientAnimation.duration = 3.0
    gradientAnimation.repeatCount = Float.infinity
    gradientLayer.add(gradientAnimation, forKey: nil)
    

    This will go between the three times equally. To change the times at which the keyframes occur, set keyTimes:

    gradientAnimation.keyTimes = [0.0, 0.4, 1.0]
    

    This will set the percentage of the animation should be passed for each element in values to reflect the current state of the animation. This should also have the same length as values.

    I don’t actually know Swift, so this should work, but I can’t guarantee it.