Touches Ended not being called
Asked Answered
T

7

20

I've playing around with recognizing the touches in an iOS Application, and I have this simple code

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
 NSLog(@"%lu",(unsigned long)[touches count]);
 [touches enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
     UITouch *touch = obj;
     CGPoint touchLocation = [touch locationInNode:self.scene];
     NSLog(@"B x:%f - y:%f",touchLocation.x,touchLocation.y);
 }];
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
 [touches enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
    UITouch *touch = obj;
    CGPoint touchLocation = [touch locationInNode:self.scene];
    NSLog(@"E x:%f - y:%f",touchLocation.x,touchLocation.y);
 }];
}

The touchesBegan is being called fine, if I place from 1 finger up to 5 fingers on the screen at the same time, I see it being called with the correct information

The same doesn't happen with touchesBegan, many time if I have 3 fingers on the screen and remove them simultaneously, I only see information on 2 touches being ended (and sometimes even 1). If I take the fingers out one at a time, the method also usually gets called 2 times (sometimes 1, although rarely it will be called the correct 3 times) As the number of touches increases, also the likely hood of some information not being shown in the touchesEnded method

Methods touchesMoved:withEvent: and touchesCancelled:withEvent: are also implemented, with the same logic

Can someone explain this behavior? Is there something I'm missing?

Taille answered 2/3, 2014 at 12:19 Comment(2)
Did you resolve this issue?Underclothing
Was there an accepted answer?Cinchona
N
38

You'd have to set recognizer.cancelsTouchesInView = false in Swift or recognizer.cancelsTouchesInView = NO; in Objective-C

Neisse answered 16/3, 2016 at 14:31 Comment(0)
A
25

Try removing any Gesture Recognizers you have on that view. They can interfere with touchesEnded.

Adalai answered 8/4, 2015 at 20:59 Comment(3)
All events ? Would swipes and touch events interfere with each other ?Respirator
I also experience the same thing, if multiple gesture recognizers interfere -touchesEnded: or -touchesCanelled: can be omitted for one of them. Important: don't rely on those methods to reset/cleanup your gesture recognizer state. Instead override -reset method for you cleanup logic which is called even though -touchesEnded: are -touchesCanelled: not.Prioress
You saved me! Thank you. Works perfect.Azpurua
M
4

You have to override all touch methods if you do not call super's implementation. So you have to also implement the touchesMoved:withEvent: and touchesCancelled:withEvent: methods. Implementations can be empty but you have to do it.

touchesBegan:withEvent:

If you override this method without calling super (a common use pattern), you must also override the other methods for handling touch events, if only as stub (empty) implementations.

Based on UIResponder Class Reference

Malikamalin answered 2/3, 2014 at 13:6 Comment(2)
I didn't add this information for brevity, but I do have all 4 methods implementedTaille
I have all 4 implemented but i touchesEnded is still not being calledStearne
P
3

Try overriding the UIView's hitTest method:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
   return self;
}

It is possible that when you lift fingers they are not recognised as being in the UIView, sotouchesEnded is not called.

Preparation answered 28/11, 2014 at 18:41 Comment(1)
I have seen this quite a few times with people stuck with similar issuesArabist
E
2
  • Tap gestures (simple, long, 2xshort, 2xfingers tap) do not allow the calls Touches Ended / Canceled if cancelsTouchesInView == NO
  • They allow its calling ONLY IF cancelsTouchesInView property is the default YES
  • Pinch gesture allows all the calls (to Touches Begin / Moved / Ended / Canceled) ONLY IF cancelsTouchesInView property is set to NO
  • If for the pinch gesture the cancelsTouchesInView property would have been YES, touchesMoved would not have been called

Inside info:

I am using:

  • 1 finger UITapGestureRecognizer
  • 1 finger UILongPressGestureRecognizer
  • 1 finger double tap UITapGestureRecognizer
  • 2 fingers tap UITapGestureRecognizer
  • 1 UIPinchGestureRecognizer

And also should receive one finger panning. But what i have found out is that the Pinch gesture was not Ending even if the user had risen one finger. Somehow iOS is still calling the Pinch's selector with "Changed" state.

My solution was to use the touchesBegin/Moved/Ended to catch the pan and use the number of active touches as safety check in case the pinch selector would be called.

Other settings i had to use in making the above configuration:

self.multipleTouchEnabled = YES;
[oneFingerTapRecognizer requireGestureRecognizerToFail:oneFingerLongPressRecognizer];
[oneFingerTapRecognizer requireGestureRecognizerToFail:oneFingerDoubleTapRecognizer];
[oneFingerLongPressRecognizer requireGestureRecognizerToFail:oneFingerDoubleTapRecognizer];
[twoFingersTapRecognizer requireGestureRecognizerToFail:twoFingersPinch];
Emilemile answered 1/10, 2018 at 13:44 Comment(0)
A
0

I had the same problem and solved it with this simple code in the touches ended:

NSInteger touchCount = 0;
for (UITouch *touch in touches) {
   touchCount++;
    if([[event allTouches]count] == touchCount){
       // do what you have to do here
    }
}

// You will get a warning here but don't care about it

I hope this help!

Adjacency answered 9/2, 2016 at 22:39 Comment(0)
K
0

I had the same problem, even after defining all four touch handlers. I also didn't have any active recognizers.

The solution for me was to simply enable multi touch events on my view, like so

self.multipleTouchEnabled = YES;

which magically solved the problem.

Note that I did get "multi touch" events even before this, i.e. events for multiple fingers at the same time, but I had the above issue that not all of them were ended properly.

Hope that helps someone! :)

Kandace answered 22/4, 2018 at 14:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.