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?

sahmed24
  • 358
  • 2
  • 3
  • 13

7 Answers7

38

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

Whakkee
  • 1,867
  • 1
  • 16
  • 18
25

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

chkimes
  • 1,127
  • 13
  • 20
  • All events ? Would swipes and touch events interfere with each other ? – 3366784 Jul 20 '16 at 03:34
  • 1
    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. – griga13 Mar 23 '17 at 12:59
  • You saved me! Thank you. Works perfect. – Baran Nov 08 '17 at 10:27
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

Rafał Sroka
  • 39,540
  • 23
  • 113
  • 143
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.

Hristo
  • 6,382
  • 4
  • 24
  • 38
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];
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Octav
  • 443
  • 3
  • 9
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!

Arthur
  • 1
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! :)

Sebastian Ärleryd
  • 1,774
  • 14
  • 19