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()
}
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.