I want to move a button from point A to point B. Point A: leadingConstraint = 120, topConstraint = 400
. Point B: leadingConstraint = 120, topConstraint = 200
. For my game purpose, I can't use frames. I also want to be able to detect a touch on it while its moving (I have no idea how to do this). I have this code where I'm attempting to move the button (using animate with duration) but whats happening is that its starting from the top left corner (small size) instead of starting from point A. It then goes to point B (normal size). Here is the code:
@IBAction func Start(sender: UIButton) {
var topAnchorforButton: NSLayoutConstraint!
let 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([
button.widthAnchor.constraintEqualToConstant(75),
button.heightAnchor.constraintEqualToConstant(75),
button.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor, constant: 120),
topAnchorforButton
])
[UIView.animateWithDuration(5.0, delay: 0.0, options: [.CurveLinear, .AllowUserInteraction], animations: {
topAnchorforButton.constant = 200
self.view.layoutIfNeeded()
}, completion: nil)]
}
func buttonPressed(sender: UIButton) {
print("hi")
}
Please help. I also don't want to use CADisplayLink
. Thanks in advance... Anton
There are 3 issues in your question:
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.