There are 3 issues in your question:
- The button must start from point A instead of the top left corner.
- The button must have a normal size instead of a small size.
- The button can be able to click while its moving.
For (1) and (2), you must move code to add button inside the viewDidLoad()
and also need to keep instances for button
and topAnchorForButton
.
Firstly, you declare two properties for button
and topAnchorForButton
.
var button: UIButton!
var topAnchorForButton: NSLayoutConstraint!
Next, you add button and set its position inside the viewDidLoad()
.
override func viewDidLoad() {
super.viewDidLoad()
button = UIButton()
button.setTitle("button", forState: .Normal)
button.setTitleColor(UIColor.blackColor(), forState: .Normal)
button.addTarget(self, action: "buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
topAnchorForButton = button.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: 400)
NSLayoutConstraint.activateConstraints([
topAnchorForButton,
button.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor, constant: 120),
])
}
func buttonPressed(sender: UIButton) {
print("hi")
}
@IBAction func start(sender: AnyObject) {
topAnchorForButton.constant = 200
[UIView.animateWithDuration(5.0, delay: 0.0, options: [.CurveLinear, .AllowUserInteraction], animations: {
self.view.layoutIfNeeded()
}, completion: nil)]
}
For (3), to hit a moving button, you need to do hit testing on the button's .layer.presentationLayer property
.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
guard let touch = (touches as NSSet).anyObject() as? UITouch else {
return
}
let touchLocation = touch.locationInView(self.view)
if button.layer.presentationLayer()?.hitTest(touchLocation) != nil {
self.buttonPressed(button)
}
}
If you want to create a new button every time the start button is pressed, you put the code to add and set its position inside the start:
method. You don't need to keep instances for button
and topAnchorForButton
anymore. You can use tag to retrieve the button.
@IBAction func start(sender: AnyObject) {
// Remove the previous button
if let previousButton = self.view.viewWithTag(100) as? UIButton {
previousButton.removeFromSuperview()
}
let button = UIButton()
button.tag = 100 // Set a tag so you can retrieve the button
button.setTitle("button", forState: .Normal)
button.setTitleColor(UIColor.blackColor(), forState: .Normal)
button.addTarget(self, action: "buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
let topAnchorForButton = button.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: 400)
NSLayoutConstraint.activateConstraints([
topAnchorForButton,
button.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor, constant: 120),
])
self.view.layoutIfNeeded()
[UIView.animateWithDuration(5.0, delay: 0.0, options: [.CurveLinear, .AllowUserInteraction], animations: {
topAnchorForButton.constant = 200
self.view.layoutIfNeeded()
}, completion: nil)]
}
Update the code for touchesBegan:withEvent event:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
guard let touch = (touches as NSSet).anyObject() as? UITouch else {
return
}
guard let button = self.view.viewWithTag(100) as? UIButton else {
return
}
let touchLocation = touch.locationInView(self.view)
if button.layer.presentationLayer()?.hitTest(touchLocation) != nil {
self.buttonPressed(button)
}
}
Note that if you don't like to use tag to retrieve the button, you can declare a property for the button.