Search code examples
iosswiftuibuttoncaanimation

Swift Change circular border color with animation


I created a circular button using swift, what I am trying to do is changing the border color with animation

I used the following code :

let color = CABasicAnimation(keyPath: "borderColor")
color.fromValue = UIColor.black.cgColor
color.toValue = UIColor.red.cgColor
color.duration = 1
color.repeatCount = 1
sender.layer.add(color, forKey: "color and width")

The border color is changing but it is not given the desire effect, it change the border color all at once. What I would like to have as effect is like your drawing over the old color, to keep it simple ==> like a progress bar where u see the old color like fade away and be replaced by the new color.

Is there is any way to do that?

Thanks for helping.

Updating code

var storkeLayer = CAShapeLayer()

@IBOutlet weak var Mybut: UIButton!
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    storkeLayer.fillColor = UIColor.clear.cgColor
    storkeLayer.strokeColor = UIColor.black.cgColor
    storkeLayer.lineWidth = 2

    // Create a rounded rect path using button's bounds.

    storkeLayer.path = CGPath.init(roundedRect: Mybut.bounds, cornerWidth: Mybut.frame.width / 2 , cornerHeight: Mybut.frame.height / 2, transform: nil)


    // Add layer to the button
    Mybut.layer.addSublayer(storkeLayer)
}


 @IBAction func bytton(_ sender: UIButton) {

    storkeLayer.fillColor = UIColor.clear.cgColor
    storkeLayer.strokeColor = UIColor.red.cgColor
    storkeLayer.lineWidth = 2

    // Create a rounded rect path using button's bounds.

    storkeLayer.path = CGPath.init(roundedRect: Mybut.bounds, cornerWidth: Mybut.frame.width / 2 , cornerHeight: Mybut.frame.height / 2, transform: nil)


    // Add layer to the button
    sender.layer.addSublayer(storkeLayer)

    // Create animation layer and add it to the stroke layer.
    let animation = CABasicAnimation(keyPath: "strokeEnd")
    animation.fromValue = CGFloat(0.0)
    animation.toValue = CGFloat(1.0)
    animation.duration = 1
   animation.fillMode = kCAFillModeForwards

   // animation.fillMode = kCAFillModeBackwards
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    storkeLayer.add(animation, forKey: "circleAnimation")



}

Solution

  • You can stroke the button's path using the following code snippet.

    @IBAction func buttonTapped(_ sender: UIButton) {
        let storkeLayer = CAShapeLayer()
        storkeLayer.fillColor = UIColor.clear.cgColor
        storkeLayer.strokeColor = UIColor.red.cgColor
        storkeLayer.lineWidth = 2
    
        // Create a rounded rect path using button's bounds.
        storkeLayer.path = CGPath.init(roundedRect: sender.bounds, cornerWidth: 5, cornerHeight: 5, transform: nil) // same path like the empty one ...
        // Add layer to the button
        sender.layer.addSublayer(storkeLayer)
    
        // Create animation layer and add it to the stroke layer.
        let animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.fromValue = CGFloat(0.0)
        animation.toValue = CGFloat(1.0)
        animation.duration = 1
        animation.fillMode = kCAFillModeForwards
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        storkeLayer.add(animation, forKey: "circleAnimation")
    }
    

    This snippet creates something like this:

    enter image description here