I am implementing custom UIGestureRecognizer. For simplicity, let assume that it recognizes gesture that consists of >1 touches.
Here is Gesture.m:
#import "Gesture.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
#define SHOW printf("%s %d %d %d\n", __FUNCTION__, self.state, touches.count, self.numberOfTouches)
@implementation Gesture
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
SHOW;
if (self.numberOfTouches==1) return;
self.state = UIGestureRecognizerStateBegan;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
SHOW;
if (self.numberOfTouches==1) return;
self.state = UIGestureRecognizerStateChanged;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
SHOW;
if (self.numberOfTouches==1) return;
self.state = UIGestureRecognizerStateEnded;
}
@end
Here is a selector:
- (IBAction)handleGesture:(Gesture *)recognizer {
printf("%s %d\n", __FUNCTION__, recognizer.state);
}
And here is an output:
-[Gesture touchesBegan:withEvent:] 0 1 1 // 1st touch began
-[Gesture touchesMoved:withEvent:] 0 1 1
-[Gesture touchesMoved:withEvent:] 0 1 1
-[Gesture touchesMoved:withEvent:] 0 1 1
-[Gesture touchesBegan:withEvent:] 0 1 2 // 2nd touch began
-[Gesture touchesMoved:withEvent:] 1 1 2 // Gesture.state==UIGestureRecognizerStateBegan but selector was not called
-[ViewController handleGesture:] 2 // UIGestureRecognizerStateChanged received.
-[Gesture touchesMoved:withEvent:] 2 2 2
-[ViewController handleGesture:] 2
-[Gesture touchesMoved:withEvent:] 2 2 2
-[ViewController handleGesture:] 2
-[Gesture touchesMoved:withEvent:] 2 2 2
-[ViewController handleGesture:] 3 // UIGestureRecognizerStateEnded received.
Why doesn’t selector receive UIGestureRecognizerStateBegan?
It wasn’t particularly obvious to me but the rules seem to be:
touchesBegan:...are subsequently considered to belong to you unless and until you set the state toUIGestureRecognizerStateFailed,UIGestureRecognizerStateEndedorUIGestureRecognizerStateCancelled;UIGestureRecognizerStateBeganthen the gesture recogniser will post that on, then automatically generateUIGestureRecognizerStateChangedwhen the touches that are now assigned to you move.So you’re not supposed to set
UIGestureRecognizerStateChangedfor yourself — just keep track of the touches and correctly post began, ended, failed and cancelled.In your case I think you just need to remove the state set within
touchesMoved:....(aside: the above is true of iOS 5 and 6; under 4 the behaviour is slightly more subtle. To work under all three versions use a construction like
if(self.state == UIGestureRecognizerStateBegan) self.state = UIGestureRecognizerStateChanged;when you know that your properties have changed)