1

In my storyboard,I have a button which i want to blink it for infinite times till the program gets killed.Here is what I have done so far,This code makes the button to animate only once.

@IBOutlet weak var blinker: UIButton!

 func Blink(){
        blinker.alpha = 0.0
        UIButton.animateWithDuration(1, animations: {
            self.blinker.alpha = 1.0
            }, completion: {
                (value: Bool) in
                println(">>> Animation done.")
        })

    }

Any help would be appreciated....

Legolas
  • 805
  • 1
  • 11
  • 24

6 Answers6

4

If you are not going to use CABasicAnimation or other variant of CAAnimation the best way is to do it recursively. For example:

func Blink(){
        blinker.alpha = 0.0
        UIButton.animateWithDuration(1, animations: {
            self.blinker.alpha = 1.0
            }, completion: {
                (value: Bool) in
                println(">>> Animation done.")
                Blink()
        })

    }

this way when the animation is finished your are calling it again, and again, and again...

Update

Please refer to Glenn's answer for the proper way to handle it. This solution may cause stack overflow issues.

Community
  • 1
  • 1
M. Porooshani
  • 1,797
  • 5
  • 34
  • 42
  • Glad it worked. by the way.. How to accept an answer: http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – M. Porooshani Sep 23 '15 at 07:15
  • 3
    IMHO infinite recursion is not a good way: Each time you call yourself you push you address on the call stack : http://www.programmerinterview.com/index.php/recursion/explanation-of-recursion/ Call Stacks, Recursion, and Stack Frames A call stack is a data structure used by the program to store information about the active subroutines (like functions in C++ or methods in Java) in a program. The main reason for having a call stack is so that the program can keep track of where a subroutine should return control to once it finishes executing. – Glenn Sep 23 '15 at 08:42
  • For example, suppose we have a method “CreateBox” which calls another method “CreateLine” in 4 different places. If the program has finished executing the method CreateLine, then it needs to know where in the CreateBox method it needs to return to. This is why the program uses a call stack – so that it can keep track of these details. This way you're creating a memory leak – Glenn Sep 23 '15 at 08:43
  • I'm with you @Glenn, If I was going to do it, I would have definitely do it using `CoreAnimation` instead of `UIView`'s `animateWithDuration()` and I suspect you're right about the call stack. – M. Porooshani Sep 23 '15 at 08:45
  • Hi M. Aravind. as M. Porooshani pointed out the recursion solutions is not really the best way to go. I tried to do it myself and provided an explanation in an answer. Please consider accepting my answer if you think it's a better solution – Glenn Sep 23 '15 at 11:45
  • Use UIView.animate or create your own UIView.beginAnimation – diegodsp Mar 08 '19 at 19:59
3

Make sure you have a button connected with an outlet to your ViewController.

Add this in your ViewDidLoad in your Viewcontroller :

    timer = NSTimer(timeInterval: 1.0, target: self, selector: "blink", userInfo: nil, repeats: true)
    NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)

and then make a function

func blink () {
        if blinkStatus == false {
            blinkingButton.tintColor = UIColor.lightGrayColor()
            blinkStatus = true
        } else {
            blinkingButton.tintColor = UIColor.blackColor()
            blinkStatus = false
        }
    }

this should do the trick. I tried it and it worked. It's based on : https://www.weheartswift.com/nstimer-in-swift/

Glenn
  • 2,808
  • 2
  • 24
  • 30
2

Although above answer will work but you could have used .autoreverse|.repeat options. That would be a cleaner way.

Ali Jawad
  • 151
  • 1
  • 13
0

Ok a bit cryptic, based somewhat on Glenn's answer I confess, but here is another answer tested on iOS 13, swift 5.

var blinkStatus:Bool?

Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { (timer) in
        if self.blinkStatus != nil {
          self.button.alpha = self.blinkStatus! ? 1:0
          self.blinkStatus = !self.blinkStatus!
        } else {
          self.button.alpha = 1
          timer.invalidate()
        }

Set blinkStatus = false to start it blinking and blinkStatus = nil to stop it. Obviously button needs to be the UIButton distance you want to blink.

user3069232
  • 8,587
  • 7
  • 46
  • 87
0

This is the way I did it:

var flashDuration: TimeInterval = 0.75

override func viewDidLoad() {
    super.viewDidLoad()

    startFlashingButton()
}

func startFlashingButton() {

    flashingButton.alpha = 0.0

    UIButton.animate(withDuration: flashDuration, animations: {

        self.flashingButton.alpha = 1.0

        }, completion: { (_) in

            self.repeatFlash()
    })
}

func repeatFlash() {

    UIButton.animate(withDuration: self.flashDuration, animations: {

        self.flashingButton.alpha = 0.0

        }, completion: { (_) in

            if self.flashDuration == 0.75 {

                self.startFlashingButton()
            }
    })
}

This would go on until the app gets killed but if you ever want to manually stop it you can just change flashDuration = 0.0

func someReasonToStopFlash() {

    flashDuration = 0.0
}

And to start it again:

func yourReasonToStartItAgain() {

    flashDuration = 0.75
    startFlashingButton()
}
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256
0
extension UIImageView{
    func startBlink1() {
        UIView.animate(withDuration: 0.8,
                       delay:0.1,
                       options:[.allowUserInteraction, .curveEaseInOut, .autoreverse, .repeat],
                       animations: { self.alpha = 0.1 },
                       completion: { [self]
                        (value: Bool) in
                        //println(">>> Animation done.")
                        startBlink2()
                       })
    }

    func startBlink2() {
        UIView.animate(withDuration: 0.8,
                       delay:0.1,
                       options:[.allowUserInteraction, .curveEaseInOut, .autoreverse, .repeat],
                       animations: { self.alpha = 1.0 },
                       completion: { [self]
                        (value: Bool) in
                        startBlink1()
                       })
    }
    
    func stopBlink() {
        layer.removeAllAnimations()
        alpha = 1
    }
}
fcdt
  • 2,371
  • 5
  • 14
  • 26