ludluck ludluck - 2 months ago 6
Swift Question

How do I properly use a timer to stagger the addition of objects to a subview?

class ViewController: UIViewController {

let manImage = UIImage(named: "man.png")

let buttons = (0..<5).map({_ in UIButton()})

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

createButtons()
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

func createButtons() {
var pos = 25
for index in 0...4 {
delay(Double(arc4random_uniform(5)) + 5) {
self.buttons[index].setBackgroundImage(self.manImage, forState: .Normal)
self.buttons[index].translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(self.buttons[index])
self.view.addConstraint(NSLayoutConstraint(
item: self.buttons[index],
attribute: .Leading,
relatedBy: .Equal,
toItem: self.view,
attribute: .Leading,
multiplier: 1,
constant: CGFloat(pos)))
pos += 10
}

}
}

func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
}


I've been using a bunch of different time delay sample code from searching, but all code results in some of the buttons to be displayed at the same time. From the line of code

delay(Double(arc4random_uniform(5)) + 5)


does this not mean to delay at least 5 seconds between each iteration of the for loop? Why does it do this?

Thank you.

Answer

A solution similar to your original approach might be to make the delay for each consecutive button relative to the previous one.

func createButtons() {
    var delayTime = 0.0
    var pos = 25
    for index in 0...4 {
        delayTime = delayTime + Double(arc4random_uniform(5)) + 5
        delay(delayTime) {
            self.buttons[index].setBackgroundImage(self.manImage, forState: .Normal)
            self.buttons[index].translatesAutoresizingMaskIntoConstraints = false
            self.view.addSubview(self.buttons[index])
            self.view.addConstraint(NSLayoutConstraint(
                item: self.buttons[index],
                attribute: .Leading,
                relatedBy: .Equal,
                toItem: self.view,
                attribute: .Leading,
                multiplier: 1,
                constant: CGFloat(pos)))
            pos += 10
        }
    }
}