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:
要想实现一个自定义手势识别器,首先在Xcode里创建一个 UIGestureRecognizer 的子类。然后,在子类的头文件中加入以下import指令。
#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:
下一步,从UIGestureRecognizerSubclass.h中拷贝以下方法声明到你的头文件;这些是你在子类中需要重写的方法。
- (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.
这些方法跟早先在“An App Receives Touches in the Touch-Handling Methods.” 中所描述的相关触摸事件处理有完全相同的签名和行为。 在所有这些需要重写的方法中,你必须调用父类的实现,即使该方法有一个null实现。
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.
注意:UIGestureRecognizerSubclass.h中的 state 特性目前是readwrite状态,而不是readonly,就跟它在UIGestureRecognizer.h中一样。 你的子类可以通过给特性分配
UIGestureRecognizerState 常量(constants)来改变其状态。
Implementing the Touch-Event Handling Methods for a Custom Gesture Recognizer
1、为自定义手势识别器实现触摸事件处理方法
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.
一个自定义手势识别器实现的核心是四个方法: touchesBegan:withEvent:
, touchesMoved:withEvent:
,touchesEnded:withEvent:
, and touchesCancelled:withEvent:
. 在这些方法中,你通过设置一个手势识别器的状态,把低层触摸事件解析为手势识别。列表1-8创建了一个离散单击勾选(checkmark)手势的手势识别器。 它记录了手势的中心点---即勾的上升开始点---这样客户就可以获取这个值。
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.
该例子只有一个单一视图,但是大多是应用程序都有多个视图。一般来说,你应该把触摸位置转换为屏幕的坐标系,这样你就可以正确的识别出跨越(span)多个视图的手势。
Implementation of a checkmark gesture recognizer
列表1-8 一个勾(checkmark)手势识别器的实现
#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; |
UIWindow *win = [self.view window]; |
CGPoint nowPoint = [touches.anyObject locationInView:win]; |
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.
离散手势和连续手势的状态过渡是不一样的,正如在 “Gesture Recognizers Operate in a Finite State Machine.” 中所描述。 当你创建一个自定义手势识别器时,你通过给它分配响应的状态来表明(indicate)它是离散手势或是连续手势。比如,列表1-8 中的复选标记(checkmark)手势识别器,它不会把状态设置为Began 或者 Changed,因为它是离散手势。
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.
当你子类化一个手势识别器时,最重要的事情是正确地设置手势识别器的state。 为了手势识别器的的交互如预期,iOS需要了解一个手势识别器的状态。比如,如果你想要实现同时识别或者要求一个手势识别器失败,iOS需要了解识别器的当前状态。
For more about creating custom gesture recognizers, see WWDC 2012: Building Advanced Gesture Recognizers.
关于创建自定义手势识别器的更多信息,请看 WWDC 2012: Building Advanced Gesture Recognizers.
Resetting a Gesture Recognizer’s State
2. 重置手势识别器的状态
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.
如果你的手势识别器过渡到Recognized/Ended, Canceled, 或者Failed状态,UIGestureRecognizer 类刚好在手势识别器过渡回Possible状态前调用reset 方法。
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.
实现reset 方法来重置任何内部状态,这样你的识别器能准备进行识别手势的一个新的尝试,正如列表1-9所示。当手势识别器从该方法返回后,它将不再接收任何在进行的触摸更新。
Resetting a gesture recognizer
列表1-9 重置一个手势识别器
- (void)reset { |
[super reset]; |
self.midPoint = CGPointZero; |
self.strokeUp = NO; |
} |