APPLE DOCUMENT:
Creating a Custom Gesture Recognizer
To implement a custom gesture recognizer, first create a subclass of UIGestureRecognizer
in Xcode. Then, add the following import
directive in your subclass’s header file:
import <UIKit/UIGestureRecognizerSubclass.h>
Next, copy the following method declarations from UIGestureRecognizerSubclass.h
to your header file; these are the methods you override in your subclass:
- (void)reset;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
These methods have the same exact signature and behavior as the corresponding touch-event handling methods described earlier in An App Receives Touches in the Touch-Handling Methods. In all of the methods you override, you must call the superclass implementation, even if the method has a null implementation.
Notice that the state
property in UIGestureRecognizerSubclass.h
is now readwrite
instead of readonly
, as it is in UIGestureRecognizer.h
. Your subclass changes its state by assigning UIGestureRecognizerState
constants to that property.
Implementing the Touch-Event Handling Methods for a Custom Gesture Recognizer
The heart of the implementation for a custom gesture recognizer are the four methods: touchesBegan:withEvent:
, touchesMoved:withEvent:
, touchesEnded:withEvent:
, and touchesCancelled:withEvent:
. Within these methods, you translate low-level touch events into gesture recognition by setting a gesture recognizer’s state. Listing 1-8 creates a gesture recognizer for a discrete single-touch checkmark gesture. It records the midpoint of the gesture—the point at which the upstroke begins—so that clients can obtain this value.
This example has only a single view, but most apps have many views. In general, you should convert touch locations to the screen’s coordinate system so that you can correctly recognize gestures that span multiple views.
Listing 1-8 Implementation of a checkmark gesture recognizer
#import <UIKit/UIGestureRecognizerSubclass.h>
// Implemented in your custom subclass
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
if ([touches count] != 1) {
self.state = UIGestureRecognizerStateFailed;
return;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
if (self.state == UIGestureRecognizerStateFailed) return;
CGPoint nowPoint = [touches.anyObject locationInView:self.view];
CGPoint prevPoint = [touches.anyObject previousLocationInView:self.view];
// strokeUp is a property
if (!self.strokeUp) {
// On downstroke, both x and y increase in positive direction
if (nowPoint.x >= prevPoint.x && nowPoint.y >= prevPoint.y) {
self.midPoint = nowPoint;
// Upstroke has increasing x value but decreasing y value
} else if (nowPoint.x >= prevPoint.x && nowPoint.y <= prevPoint.y) {
self.strokeUp = YES;
} else {
self.state = UIGestureRecognizerStateFailed;
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
if ((self.state == UIGestureRecognizerStatePossible) && self.strokeUp) {
self.state = UIGestureRecognizerStateRecognized;
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
self.midPoint = CGPointZero;
self.strokeUp = NO;
self.state = UIGestureRecognizerStateFailed;
}
State transitions for discrete and continuous gestures are different, as described in Gesture Recognizers Operate in a Finite State Machine. When you create a custom gesture recognizer, you indicate whether it is discrete or continuous by assigning it the relevant states. As an example, the checkmark gesture recognizer in Listing 1-8 never sets the state to Began or Changed, because it’s discrete.
The most important thing you need to do when subclassing a gesture recognizer is to set the gesture recognizer’s state
accurately. iOS needs to know the state of a gesture recognizer in order for gesture recognizers to interact as expected. For example, if you want to permit simultaneous recognition or require a gesture recognizer to fail, iOS needs to understand the current state of your recognizer.
For more about creating custom gesture recognizers, see WWDC 2012: Building Advanced Gesture Recognizers.
Resetting a Gesture Recognizer’s State
If your gesture recognizer transitions to Recognized/Ended, Canceled, or Failed, the UIGestureRecognizer
class calls the reset
method just before the gesture recognizer transitions back to Possible.
Implement the reset
method to reset any internal state so that your recognizer is ready for a new attempt at recognizing a gesture, as in Listing 1-9. After a gesture recognizer returns from this method, it receives no further updates for touches that are in progress.
Listing 1-9 Resetting a gesture recognizer
- (void)reset {
[super reset];
self.midPoint = CGPointZero;
self.strokeUp = NO;
}
对于手势的一点理解: