I have a tap gesture on a UILabel who's translation is being animated. Whenever you tap on the label during the animation there's no response from the tap gesture.
Here's my code:
label.addGestureRecognizer(tapGesture)
label.userInteractionEnabled = true
label.transform = CGAffineTransformMakeTranslation(0, 0)
UIView.animateWithDuration(12, delay: 0, options: UIViewAnimationOptions.AllowUserInteraction, animations: { () -> Void in
label.transform = CGAffineTransformMakeTranslation(0, 900)
}, completion: nil)
Gesture code:
func setUpRecognizers() {
tapGesture = UITapGestureRecognizer(target: self, action: "onTap:")
}
func onTap(sender : AnyObject) {
print("Tapped")
}
Any ideas? Thanks :)
You will not be able to accomplish what you are after using a tapgesture for 1 huge reason. The tapgesture is associated with the frame of the label. The labels final frame is changed instantly when kicking off the animation and you are just watching a fake movie(animation). If you were able to touch (0,900) on the screen it would fire as normal while the animation is occuring. There is a way to do this a little bit different though. The best would be to uses touchesBegan. Here is an extension I just wrote to test my theory but could be adapted to fit your needs.For example you could use your actual subclass and access the label properties without the need for loops.
extension UIViewController{
public override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
guard let touch = touches.first else{return}
let touchLocation = touch.locationInView(self.view)
for subs in self.view.subviews{
guard let ourLabel = subs as? UILabel else{return}
print(ourLabel.layer.presentationLayer())
if ourLabel.layer.presentationLayer()!.hitTest(touchLocation) != nil{
print("Touching")
UIView.animateWithDuration(0.4, animations: {
self.view.backgroundColor = UIColor.redColor()
}, completion: {
finished in
UIView.animateWithDuration(0.4, animations: {
self.view.backgroundColor = UIColor.whiteColor()
}, completion: {
finished in
})
})
}
}
}
}
You can see that it is testing the coordinates of the CALayer.presentationLayer()..That's what I was calling the movies. To be honest, I have still not wrapped my head completely around the presentation layer and how it works.
If you want to see the animation, you need to put it in the onTap handler.
let gesture = UITapGestureRecognizer(target: self, action: "onTap:")
gesture.numberOfTapsRequired = 1
label.addGestureRecognizer(gesture)
label.userInteractionEnabled = true
label.transform = CGAffineTransformMakeTranslation(0, 0)
UIView.animateWithDuration(12, delay: 3, options: [.AllowUserInteraction], animations: { () -> Void in
label.transform = CGAffineTransformMakeTranslation(0, 900)
}, completion: nil)
func onTap(sender : AnyObject)
{
print("Tapped")
}
For your tap gesture to work, you have to set the number of taps. Add this line:
tapGesture.numberOfTapsRequired = 1
(I'm assuming that tapGesture
is the same one you call label.addGestureRecognizer(tapGesture)
with)
Below is a more generic answer based on the answer from @agibson007 in Swift 3.
This didn't solve my issue immediately, because I had additional subviews covering my view. If you have trouble, try changing the extension type and writing print statements for touchLocation
to find out when the function is firing. The description in the accepted answer explains the issue well.
extension UIViewController {
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let touchLocation = touch.location(in: self.view)
for subview in self.view.subviews {
if subview.tag == VIEW_TAG_HERE && subview.layer.presentation()?.hitTest(touchLocation) != nil {
print("[UIViewController] View Touched!")
// Handle Action Here
}
}
}
}