Reputation: 1466
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?
Upvotes: 4
Views: 2637
Reputation: 100622
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 to UIGestureRecognizerStateFailed
, UIGestureRecognizerStateEnded
or UIGestureRecognizerStateCancelled
;UIGestureRecognizerStateBegan
then the gesture recogniser will post that on, then automatically generate UIGestureRecognizerStateChanged
when the touches that are now assigned to you move.So you're not supposed to set UIGestureRecognizerStateChanged
for 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)
Upvotes: 3