-1

I used the code below to create a label every time a button is pressed, then have the label move to a specific location, and then have it delete.

My problem is it can't create multiple labels because it's deleting the label way too soon, because it removes everything named label.

How can I fix this so it creates multiple labels that only get deleted when a label individually completes its animation?

A solution I've thought of, but can't figure out is where you have it create a label with a different name such as label1, label2, and so on, so that way it can delete a specific label when it completes it's animation, instead of deleting all of them.

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

func createLabel() {

    // Find the button's width and height
    let labelWidth = label.frame.width

    // Find the width and height of the enclosing view
    let viewWidth = self.view.frame.width

    // Compute width and height of the area to contain the button's center
    let xwidth = viewWidth - labelWidth

    // Generate a random x and y offset
    let xoffset = CGFloat(arc4random_uniform(UInt32(xwidth)))

    // Offset the button's center by the random offsets.
    label.center.x = xoffset + labelWidth / 2
    label.center.y = 300

    label.font = UIFont(name:"Riffic Free", size: 18.0)
    label.textColor = UIColor.white
    label.textAlignment = .center
    label.text = "+1"
    self.view.addSubview(label)
}

func clearLabel() {
    UIView.animate(withDuration: 0.9, delay: 0.4, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.0, options: .curveLinear, animations: {

        self.label.center = CGPoint(x: 265, y: 75 )

    }, completion: { (finished: Bool) in
        self.label.removeFromSuperview()
    })
}

@IBAction func clicked(_ sender: Any) {
    createLabel()
    clearLabel()
}
Nathan C
  • 214
  • 1
  • 3
  • 10

1 Answers1

1

The problem is with this code:

@IBAction func clicked(_ sender: Any) {
    createLabel()
    clearLabel()
}

There are two issues. The first is that you are doing the animation and removal before you even give the label a chance to become part of the interface. You need to introduce a delay (you can use my delay utility, https://stackoverflow.com/a/24318861/341994):

@IBAction func clicked(_ sender: Any) {
    createLabel()
    delay(0.1) {
        clearLabel()
    }
}

The second problem, as you have rightly said, is that you have one label instance variable, which you are using to share the label between createLabel and clearLabel. Thus another label cannot come along during the animation.

But you don't actually need any instance variable. So get rid of your label declaration completely! Instead, modify createLabel so that it actually creates the label (i.e. calls UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 100))) as a local variable, and then returns a reference to label it creates, like this:

func createLabel() -> UILabel {
    let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
    // ...
    return label
}

... And then just have clearLabel take that same label as a parameter so that it moves that label and removes it at the end of the animation, like this:

func clearLabel(_ label : UILabel) {
    // ...
}

Your clicked implementation will thus look like this, passing the label out of createLabel and into clearLabel:

@IBAction func clicked(_ sender: Any) {
    let label = self.createLabel()
    delay(0.1) {
        self.clearLabel(label)
    }
}

(The remaining details of modifying createLabel and clearLabel to make that work are left as an exercise for the reader.)

Now each tap on the button creates and animates and removes a new label, independently of whatever else may have happened before.

enter image description here

matt
  • 447,615
  • 74
  • 748
  • 977
  • I changed clicked into what you suggested and implemented your delay function. – Nathan C May 19 '18 at 18:47
  • I don't understand what you mean for the modification of `createLabel`, can you elaborate? – Nathan C May 19 '18 at 22:04
  • I don't understand how to modify `createLabel` and create the parameter function because if delete the declaration of `label` then the random location spawn of the label function won't work. Can you post code to go with it? – Nathan C May 19 '18 at 22:32
  • Can you update your answer with the code you had for `clearLabel`? – Nathan C May 20 '18 at 15:00
  • `clearLabel` did not change significantly. Neither did `createLabel`. Basically I'm using your code throughout. The only difference for `clearLabel` is that now there is no `self.label`; instead, there is the label that is passed _into_ `clearLabel` as a _parameter_, as I showed in my answer. – matt May 20 '18 at 15:28
  • See revised answer. – matt May 20 '18 at 16:34
  • I don't know what you are doing now. I'm showing you what I did in order to implement your code, and you can see from the screencast that it does what you want done. There should be _no_ reference to `self` anywhere in your code at this point; the `label` is the _local_ variable `label` in each method. – matt May 20 '18 at 16:36