9

For some reason this isn't working for me:

let color = CABasicAnimation(keyPath: "borderColor")
color.fromValue = sender.layer.borderColor;
color.toValue = UIColor.redColor().CGColor;
color.duration = 2;
color.repeatCount = 1;
sender.layer.addAnimation(color, forKey: "color and width");

I'm not getting any animation to occur.

Chase Roberts
  • 9,082
  • 13
  • 73
  • 131
  • what result does this code give? – actual_kangaroo Mar 09 '15 at 07:37
  • What is not working? Include the error message and the expected result in an edit of your question (don't comment on comments, and don't include **Edit** or **Update** in your elaboration, we can see what changed from the edit history). – Anthon Mar 09 '15 at 08:52

5 Answers5

12

Swift 4 UIView extension:

extension UIView {
  func animateBorderColor(toColor: UIColor, duration: Double) {
    let animation = CABasicAnimation(keyPath: "borderColor")
    animation.fromValue = layer.borderColor
    animation.toValue = toColor.cgColor
    animation.duration = duration
    layer.add(animation, forKey: "borderColor")
    layer.borderColor = toColor.cgColor
  }
}

And then just use it by writing:

myView.animateBorderColor(toColor: .red, duration: 0.5)
budiDino
  • 13,044
  • 8
  • 95
  • 91
8

You have to use the same key name. You also forgot to add a border width and color to your layer before animating it. Try like this:

let color = CABasicAnimation(keyPath: "borderColor")

@IBAction func animateBorder(sender: AnyObject) {
    color.fromValue = UIColor.greenColor().CGColor
    color.toValue = UIColor.redColor().CGColor
    color.duration = 2
    color.repeatCount = 1
    sender.layer.borderWidth = 2
    sender.layer.borderColor = UIColor.greenColor().CGColor
    sender.layer.addAnimation(color, forKey: "borderColor")
}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • After playing with it some more. I think the problem is the fromColor. It's not reading the sender.layer.borderColor. – Chase Roberts Mar 09 '15 at 04:28
  • color.fromValue = sender.layer.borderColor also works for me here – Leo Dabus Mar 09 '15 at 04:39
  • The problem was the key name forKey: "color and width". If you want to animate color and border you need to create one CABasicAnimation for each property (borderColor and borderWidth) – Leo Dabus Mar 09 '15 at 05:05
  • calling sender.layer.addAnimation(color, forKey: "color") works. It's when I change it to color.fromValue = sender.layer.borderColor that things break. I don't get it, but that's what's happening. – Chase Roberts Mar 09 '15 at 18:06
4

(Swift 5, Xcode 11, iOS 13)

For anyone who is wanting to change border color and width at the same time, the following code is working for me & the animation looks very smooth. Maybe someone else knows of a way to combine both into one?

let borderColorAnimation: CABasicAnimation = CABasicAnimation(keyPath: "borderColor")
borderColorAnimation.fromValue = layer.borderColor
borderColorAnimation.toValue = toColor.cgColor
borderColorAnimation.duration = animationDuration
layer.add(borderColorAnimation, forKey: "borderColor")
layer.borderColor = toColor.cgColor

let borderWidthAnimation: CABasicAnimation = CABasicAnimation(keyPath: "borderWidth")
borderWidthAnimation.fromValue = layer.borderWidth
borderWidthAnimation.toValue = toWidth
borderWidthAnimation.duration = animationDuration
layer.add(borderWidthAnimation, forKey: "borderWidth")
layer.borderWidth = toWidth
Trev14
  • 3,626
  • 2
  • 31
  • 40
  • To combine animations we can use CAAnimationGroup. let animationGroup = CAAnimationGroup() animationGroup.animations = [colorsAnimation] animationGroup.duration = duration layer.add(animationGroup, forKey: "animation-group") – landnbloc Jan 09 '21 at 15:41
3

I created a Swift 4 function extension to CALayer for this, to which you can pass the starting and ending UIColors as well as the duration for the animation:

extension CALayer {

func animateBorderColor(from startColor: UIColor, to endColor: UIColor, withDuration duration: Double) {
    let colorAnimation = CABasicAnimation(keyPath: "borderColor")
    colorAnimation.fromValue = startColor.cgColor
    colorAnimation.toValue = endColor.cgColor
    colorAnimation.duration = duration
    self.borderColor = endColor.cgColor
    self.add(colorAnimation, forKey: "borderColor")
}

Note that for this to work, you should have already set a borderWidth and then call animateBorderColor:

yourView.layer.borderWidth = 1.5
yourView.layer.animateBorderColor(from: UIColor.green, to: UIColor.red, withDuration: 2.0)
Jonathan Cabrera
  • 1,656
  • 1
  • 19
  • 20
2

I don't know why, but for some reason calling:

color.fromValue = sender.layer.borderColor

doesn't work. The color isn't being read correctly or something. I changed it to:

let color = CABasicAnimation(keyPath: "borderColor");
color.fromValue = UIColor.greenColor().CGColor;
color.toValue = UIColor.redColor().CGColor;
color.duration = 2;
color.repeatCount = 1;
sender.layer.addAnimation(color, forKey: "color and width");

And then things started working as expected.

Chase Roberts
  • 9,082
  • 13
  • 73
  • 131