【iOS开发】事件处理之手势识别(一)

手势识别

手势识别将低级别事件处理代码转换成更高一级的行动。它们是对连接至一个视图,它允许,以便向操作进行响应的控制的方式做对象。手势识别解释触摸以确定它们是否对应于特定的手势,诸如滑动,挤压或转动。如果他们认识到自己指定的姿态,他们发送一个动作消息给目标对象。目标对象通常是视图的视图控制器,如图其中响应于所述姿态图1-1。这种设计模式是既强大又简单; 您可以动态地确定哪个视图被响应,你可以添加手势识别到一个视图上,而无需判断子视图是否响应。

这里写图片描述
图1-1 连接到一个视图上的手势

使用手势识别简化事件处理

苹果系统UIKit的框架提供了检测常见的手势预定义手势识别。最好是使用预定义手势这样子可以减少很多代码量。此外,使用标准的手势识别,而不是在app中定义为了满足用户期望的某种自定义手势识别。

如果你希望你的应用程序来识别独特的手势,比如一个标志或旋涡状运动,你可以创建自己的自定义手势识别。要了解如何设计和实现自己的手势识别,请参阅创建自定义手势识别

常见的手势

当设计你的应用程序,可以考虑要启用什么手势。然后,对于每个姿态,确定中列出的预定手势识别之一是否表1-1是足够的。
这里写图片描述
表1-1 UIKit框架的手势识别器类

您的应用程序应该响应用户期望的手势。例如,一个捏应该放大和缩小,而一个水龙头应该选择什么。有关如何正确地使用手势准则,请参阅应用程序响应手势,而不是点击次数。

注: 在iOS系统7及更高版本,期望用户从屏幕揭示控制中心的底部向上滑动。如果iOS的确定开始于屏幕底部的触摸应揭露控制中心,它不提供的手势当前正在运行的应用程序。如果iOS的确定触摸不应泄露控制中心,所述触摸可以稍微到达应用之前延迟。

视图关联手势

每一个手势识别与一个视图相关联。与此相反,一个视图可以有多个手势识别,因为单一视图可能以许多不同的手势作出响应。对于一个手势识别器识别发生在特定视图,您必须具体响应。当用户触摸该视图中,手势识别接收到视图对象之前确实发生了触摸的消息。其结果是,该手势识别可以对触摸作出响应代表视图的。

手势触发操作消息

当一个手势识别承认其指定的姿态,它发送一个动作消息到其目标。要创建一个手势识别,您的目标和行动初始化。

离散和连续手势

手势是离散或连续的。一个离散的手势,诸如抽头,发生一次。一个连续的手势,如捏,发生经过一段时间。对于离散手势,手势识别将其目标单一动作的消息。连续比划了手势识别不停发送动作消息给它的目标,直到多点触控序列结束,如图图1-2。
这里写图片描述
这里写图片描述
图1-2 离散和连续的手势

回应与手势识别活动

有三件事情你做一个内置手势识别器添加到您的应用程序:

创建和配置一个手势识别的实例。
此步骤包括分配一个目标,作用,有时分配特定姿势的属性(如numberOfTapsRequired)。

附加手势识别到视图。
落实处理手势操作方法。

使用Interface Builder一个手势识别添加到您的应用程序

在界面生成器在Xcode中,添加一个手势识别到你的应用程序,你以同样的方式添加任何对象到用户界面 -drag从对象库的手势识别到视图。当你这样做时,手势识别自动成为连接到该视图。您可以检查哪些查看手势识别器连接到,如果有必要,更改笔尖文件中的连接。

您所创建的手势识别对象后,您需要创建和连接动作的方法。每当连接的手势识别承认其姿态时调用此方法。如果您需要引用此操作方法之外的手势识别,还应该创建和连接插座的手势识别。您的代码应该类似于清单1-1。

清单1-1 添加一个手势识别与Interface Builder中您的应用程序

@interface APLGestureRecognizerViewController ()
@property (nonatomic, strong) IBOutlet UITapGestureRecognizer *tapRecognizer;
@end

@implementation
- (IBAction)displayGestureForTapRecognizer:(UITapGestureRecognizer *)recognizer
     // Will implement method later...
}
@end
添加一个手势识别编程

您可以创建通过分配和编程手势识别初始化一个具体的实例UIGestureRecognizer子类,如UIPinchGestureRecognizer。当初始化手势识别,指定目标对象和行动选择,如清单1-2。通常情况下,目标对象是视图的视图控制器。

如果以编程方式创建一个手势识别,您需要将它连接到使用视图addGestureRecognizer: 。方法清单1-2创建一个单一的水龙头手势识别,指定一个水龙头是必需的手势识别,然后在附加手势识别对象的视图。通常情况下,你在你的视图控制器来创建一个手势识别的viewDidLoad方法,如图清单1-2。

清单1-2 编程方式创建一个单一的点击手势识别

- (void)viewDidLoad {
     [super viewDidLoad];

     // Create and initialize a tap gesture
     UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc]
          initWithTarget:self action:@selector(respondToTapGesture:)];

     // Specify that the gesture must be a single tap
     tapRecognizer.numberOfTapsRequired = 1;

     // Add the tap gesture recognizer to the view
     [self.view addGestureRecognizer:tapRecognizer];

     // Do any additional setup after loading the view, typically from a nib
}
响应离散手势

当你创建一个手势识别,您识别器连接到操作方法。使用这种操作方法对你的手势识别的手势回应。清单1-3提供响应离散姿态的一个例子。当用户点击该手势识别器连接到视图,视图控制器显示,上面写着图像视图中的“抽头”。showGestureForTapRecognizer:方法决定从识别的视图的姿态的位置locationInView:属性,然后显示在该位置的图像。

注: 接下来的三个代码示例是从简单的手势识别的示例代码项目,它可以检查更多的上下文。
清单1-3 处理双点击手势

- (IBAction)showGestureForTapRecognizer:(UITapGestureRecognizer *)recognizer {
       // Get the location of the gesture
      CGPoint location = [recognizer locationInView:self.view];

       // Display an image view at that location
      [self drawImageForGestureRecognizer:recognizer atPoint:location];

       // Animate the image view so that it fades out
      [UIView animateWithDuration:0.5 animations:^{
           self.imageView.alpha = 0.0;
      }];
}

每个手势识别器都有它自己的属性集。例如,在列表1-4中,showGestureForSwipeRecognizer:方法使用扫掠姿态识别的 方向属性,以确定该用户刷卡向左或向右。然后,它使用该值来使图像淡出在相同的方向上滑动。

清单1-4 回答一个向左或向右滑动手势

// Respond to a swipe gesture
- (IBAction)showGestureForSwipeRecognizer:(UISwipeGestureRecognizer *)recognizer {
       // Get the location of the gesture
       CGPoint location = [recognizer locationInView:self.view];

       // Display an image view at that location
       [self drawImageForGestureRecognizer:recognizer atPoint:location];

       // If gesture is a left swipe, specify an end location
       // to the left of the current location
       if (recognizer.direction == UISwipeGestureRecognizerDirectionLeft) {
            location.x -= 220.0;
       } else {
            location.x += 220.0;
       }

       // Animate the image view in the direction of the swipe as it fades out
       [UIView animateWithDuration:0.5 animations:^{
            self.imageView.alpha = 0.0;
            self.imageView.center = location;
       }];
}
应对持续手势

连续的手势让你的应用程序,因为它正在发生的回应姿态。例如,您的应用程序可以在用户正在捏缩放或允许用户拖动屏幕上的对象。

清单1-5在相同的旋转角作为手势显示“旋转”图像,并且当用户停止旋转,动画图像,这样它代替淡出同时旋转回水平。当用户旋转他的手指时,showGestureForRotationRecognizer:直到两个手指抬起方法也在不断地调用。

清单1-5 响应旋转手势

// Respond to a rotation gesture
- (IBAction)showGestureForRotationRecognizer:(UIRotationGestureRecognizer *)recognizer {
       // Get the location of the gesture
       CGPoint location = [recognizer locationInView:self.view];

       // Set the rotation angle of the image view to
       // match the rotation of the gesture
       CGAffineTransform transform = CGAffineTransformMakeRotation([recognizer rotation]);
       self.imageView.transform = transform;

       // Display an image view at that location
       [self drawImageForGestureRecognizer:recognizer atPoint:location];

      // If the gesture has ended or is canceled, begin the animation
      // back to horizontal and fade out
      if (([recognizer state] == UIGestureRecognizerStateEnded) || ([recognizer state] == UIGestureRecognizerStateCancelled)) {
           [UIView animateWithDuration:0.5 animations:^{
                self.imageView.alpha = 0.0;
                self.imageView.transform = CGAffineTransformIdentity;
           }];
      }

}

各方法被调用时,该图像被设定为在不透明drawImageForGestureRecognizer:方法。当手势完成时,图像被设定为在透明animateWithDuration:方法。该showGestureForRotationRecognizer:方法确定是否姿态通过检查手势识别的状态完成。这些状态进行了详细解释了手势识别的有限状态机操作。

如何定义手势识别交互

通常情况下,当你添加手势识别到你的应用程序,你需要具体您想如何识别器相互或应用中的任何其他触摸事件处理代码交互。要做到这一点,首先需要了解一点关于手势识别是如何工作的。

有限状态机上的手势识别操作

手势识别从一个状态到另一个的过渡中的预定方式。从每个状态,他们可以转移到基于其是否符合一定的条件下几个可能的下一个状态之一。确切的状态机的变化取决于手势识别是否是离散的或连续的,如在示出图1-3。所有手势识别器的可能状态(开始UIGestureRecognizerStatePossible)。他们分析,他们收到的多点触控序列,并在分析过程中,他们要么承认或不承认一个手势。没有认识到一个手势是指手势识别转换为失败状态(UIGestureRecognizerStateFailed)。
这里写图片描述
图1-3 状态机的手势识别

当一个离散的手势识别器识别到它的手势,从可能的手势识别过渡到认可(UIGestureRecognizerStateRecognized)和识别已完成。

对于连续的手势,从可能开始手势识别转换(UIGestureRecognizerStateBegan当手势首次承认)。然后,从转换到开始改变(UIGestureRecognizerStateChanged),并继续从改变姿态发生改变移动。当用户的最后手指从视图提起时,手势识别转变到端状态(UIGestureRecognizerStateEnded)和识别已完成。请注意,端状态是可识别的状态的别名。

一种用于连续手势识别也可以从过渡更改为已取消(UIGestureRecognizerStateCancelled),如果它决定该手势不再符合预期的模式。

每当一个手势识别状态改变时,手势识别器发送一个动作消息到它的目标,除非它转换到失败或取消。因此,当它从可能的转换,以识别一个离散手势识别仅发送一个动作信息。连续的手势识别器发送,因为它改变了许多状态采取行动的消息。

当一个手势识别达到认可(或终止)状态时,它复位其状态恢复到可能的。过渡回可能不会触发动作的消息。

多手势识别器交互

一个视图可以有多个手势识别器连接到它。使用视图的gestureRecognizers属性,以确定哪些手势识别连接到的图。您还可以动态改变如何视图通过添加或从与一个视图中删除一个手势识别手势处理addGestureRecognizer:和removeGestureRecognizer:方法,分别为。

如果视图连接多个手势识别器,你可能要改变竞争的手势识别如何接收并分析触摸事件。默认情况下,存在对手势识别首先接收触摸没有固定的顺序,基于这个原因,倒是可以每次都被传递给手势识别不同的顺序。您可以覆盖此默认行为:

指定一个手势识别应分析之前,另一个手势识别触摸。
允许两个手势识别到同时操作。
从分析触摸防止手势识别。
使用UIGestureRecognizer类的方法,委托方法和重载方法,通过子类来实现这些行为。

声明一个特定顺序的两个手势识别

试想一下,你要认识到轻扫和平移手势,并且希望这两个手势来触发不同的动作。默认情况下,当用户轻扫,所述手势被解释为点击。这是因为一个轻扫手势符合被解释为一个点击(连续手势)符合被解释为轻扫的必要条件(一个离散手势)之前的必要条件。

对于您的观点认识到这两个滑动和平移,你想要的平移手势识别器前挥动手势识别来分析触摸事件。如果扫动手势识别器确定该触摸是一个滑动,平移手势识别从未需要分析的触感。如果扫动手势识别器确定触摸不是轻扫,它移动到失败状态和平移手势识别应该开始分析触摸事件。

在此之前的iOS 7,如果一个手势识别需要另一个手势识别失败,您可以使用requireGestureRecognizerToFail:设置在创建时的两个对象之间的永久关系。当在别处不创建手势识别能正常工作的应用程式或在一个框架和一组手势识别的保持相同。

在iOS中7,UIGestureRecognizerDelegate介绍了两种方法,允许在运行时通过手势识别委托对象指定故障要求:

gestureRecognizer:shouldRequireFailureOfGestureRecognizer:
gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:
注: UIGestureRecognizerSubclass定义,让子类来定义类级故障要求的能力类似的方法(要了解更多信息,请参阅UIGestureRecognizer类参考)。
对于这两种方法中,手势识别委托称为每次识别尝试,这意味着故障需求可以被懒惰地确定一次。这也意味着,你可以设置不同的视图层次识别之间失败的需求。

其中,动态破坏要求是有用的情况的一个例子是在附加一个屏幕边缘平移手势识别到一个视图的应用程式。在这种情况下,您可能希望使用该视图的子树相关要求屏幕边缘手势识别失败,这样就可以防止当对方识别得到启动识别过程后取消可能出现的任何故障的图形所有其他相关的手势识别。要做到这一点,您可以使用类似于所示的代码代码清单1-6。

清单1-6 设置故障要求

UIScreenEdgePanGestureRecognizer *myScreenEdgePanGestureRecognizer;
...
myScreenEdgePanGestureRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleScreenEdgePan:)];
myScreenEdgePanGestureRecognizer.delegate = self;
// Configure the gesture recognizer and attach it to the view.
...
 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    BOOL result = NO;
    if ((gestureRecognizer == myScreenEdgePanGestureRecognizer) && [[otherGestureRecognizer view] isDescendantOfView:[gestureRecognizer view]]) {
        result = YES;
    }
    return result;
 }
预防手势识别器接收分析的触摸

您可以通过添加一个改变一个手势识别的行为委托对象的手势识别。该UIGestureRecognizerDelegate协议提供了一组就可以防止手势识别从分析的方式接触。您使用的gestureRecognizer:shouldReceiveTouch:方法或gestureRecognizerShouldBegin:方法,两者都是可选的方法UIGestureRecognizerDelegate协议。

当触摸开始,如果你能马上判断你的手势识别是否应该考虑到触摸,使用gestureRecognizer:shouldReceiveTouch:方法。这种方法被称为每次有新的触摸时间。返回NO防止被通知触摸发生了手势识别器。默认值是YES。此方法不改变手势识别的状态。

清单1-7使用gestureRecognizer:shouldReceiveTouch:委托方法,以防止自来水手势识别接收是一个自定义子视图内的触摸。当触摸发生时,gestureRecognizer:shouldReceiveTouch:方法被调用。它确定用户是否触摸了定制视图,如果是这样,防止了抽头手势识别从接收到触摸事件。

清单1-7 接收触摸防止手势识别

- (void)viewDidLoad {
    [super viewDidLoad];
    // Add the delegate to the tap gesture recognizer
    self.tapGestureRecognizer.delegate = self;
}

// Implement the UIGestureRecognizerDelegate method
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    // Determine if the touch is inside the custom subview
    if ([touch view] == self.customSubview){
        // If it is, prevent all of the delegate's gesture recognizers
        // from receiving the touch
        return NO;
    }
    return YES;
}

如果你需要尽可能长时间地等待决定一个手势识别是否应该分析触摸前,使用gestureRecognizerShouldBegin:委托方法。一般情况下,如果你有一个使用此方法的UIView或者UIControl子类有与手势识别竞争定制的触摸事件处理。返回否会导致手势识别立即失败,这使得其它触摸处理继续。这种方法被称为当一个手势识别试图转型走出 ​​的可能状态,如果手势识别将防止视图或控制接收触摸。

您可以使用gestureRecognizerShouldBegin: UIView的方法,如果您的视图或视图控制器不能是手势识别的委托。方法签名和实现是相同的。

同时允许手势识别

默认两个手势识别不能同时认识到它们的各自的手势。但假设,例如,你希望用户能够捏和旋转在同一时间的视图。你需要通过执行来改变默认的行为gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:法,一个可选的方法UIGestureRecognizerDelegate 协议。当一个手势一个手势识别的分析将从承认其姿态,反之亦然阻塞另一个手势识别这种方法被调用。这个方法返回NO默认。返回YES,当你希望两个手势识别同时分析他们的手势。

注意: 您需要实现一个委托,并返回YES上只有你的手势识别器之一,允许同时识别。然而,这也意味着,返回NO不一定防止同时承认,是因为其他的手势识别的委托可以返回YES。

指定两个手势识别器之间的单向关系

如果你想控制两个识别如何相互交互,但是你需要指定一个单向的关系,你可以重写无论是canPreventGestureRecognizer:canBePreventedByGestureRecognizer:子类的方法来返回NO(默认值是YES)。例如,如果你想有一个旋转手势,以防止捏的手势,但你不想捏的姿态,以防止旋转手势,你可以指定:

[rotationGestureRecognizer canPreventGestureRecognizer:pinchGestureRecognizer];

并覆盖旋转手势识别的子类方法返回NO。有关如何继承的更多信息UIGestureRecognizer,请参阅创建自定义手势识别。

如果没有手势应防止其他,使用gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:方法,如描述的行政法规同时手势识别。缺省情况下,捏合姿态防止旋转,反之亦然因为有两个手势不能在同一时间进行识别。

与其他用户界面交互控制

在iOS中6.0及更高版本,默认的控制措施防止重叠的手势识别器的行为。例如,一个按钮的默认操作是一个水龙头。如果连接到一个按钮的父视图一个水龙头手势识别,以及用户点击按钮,然后按钮的操作方法接收触摸事件,而不是手势识别。这仅适用于重叠的控制,其中包括默认动作手势识别:

在一个手指只需轻轻的UIButtonUISwitchUIStepperUISegmentedControlUIPageControl
上的旋钮的单个手指滑动UISlider,在平行于滑动件的方向。
上的旋钮的单个手指平移手势UISwitch,在平行于开关方向。
如果您有这些控件之一的自定义子类,要更改默认操作,直接连接一个手势识别来控制,而不是父视图。接着,手势识别首先接收触摸事件。与往常一样,一定要读的iOS人机界面指南,以确保您的应用程序提供了一个直观的用户体验,覆盖标准控件的默认行为时尤其如此。

手势识别解释原始的触摸事件

到目前为止,你已经了解的手势,以及如何您的应用程序可以识别并作出回应。但是,要创建一个自定义的手势识别器或控制手势识别器如何与视图的触摸事件处理交互,你需要更具体的思考和触摸事件的条款。

一个事件包含了所有当前的多点触控序列润色

在iOS中,一个触摸在屏幕上手指的存在或运动。手势具有一个或多个触摸,这是由表示UITouch对象。例如,一个夹紧密手势具有两个触摸两屏幕从相反的方向朝向彼此移动的手指。

一个事件包含多点触控序列过程中发生的所有接触。当手指触摸屏幕并在最后一个手指抬起结束的多触摸序列开始。作为一个手指的移动,iOS的发送触摸对象的事件。一个多点触摸事件由a表示的UIEvent类型的对象UIEventTypeTouches。

每个触摸对象只跟踪一个手指,只有持续的时间为多点触控序列。的序列期间,UIKit的跟踪手指,并更新所述触摸对象的属性。这些属性包括所述触摸的阶段,其在视图中的位置,它以前的位置,并且它的时间戳记。

在触摸阶段表示的触摸开始时,无论是移动或固定的,并且它结束-即当是,当手指不再触摸屏幕。作为描绘的图1-4中,一个应用程序中的任何接触的每个阶段接收事件对象。
这里写图片描述
图1-4 多点触控序列和触摸阶段
多点触摸序列和触摸阶段
注: 手指比鼠标指针不太精确。当用户触摸屏幕时,接触面积实际上是椭圆形的,并趋向于比用户期望略低。这种“接触补片”变化的基础上的手指的大小和方向,压力的量,使用哪个手指,以及其他因素。底层的多点触控系统,分析这些信息,为您和计算的单一接触点,所以你不需要编写自己的代码来做到这一点。

一个App倒是接收的触摸处理方法

在多点触控序列,应用程序发送的时候有一个给定的触摸阶段新的或更改触摸这些消息; 它调用的
touchesBegan:withEvent:方法,当一个或多个手指触摸到屏幕上。
touchesMoved:withEvent:方法,当一个或多个手指移动。
touchesEnded:withEvent:方法,当一个或多个手指从屏幕上抬起方法。
touchesCancelled:withEvent:方法,当触摸序列由一个系统事件取消,例如传入的电话呼叫的方法。
这些方法的每一个与触摸阶段相关联; 例如,touchesBegan:withEvent:方法所关联UITouchPhaseBegan。触摸对象的相位被存储在它的相位 特性。

注意: 这些方法不与手势识别状态,如相关UIGestureRecognizerStateBegan和UIGestureRecognizerStateEnded。手势识别状态严格表示手势识别自身的相位,而不是正在识别的触摸对象的相位。
调节触摸便可欣赏到交货

有时可能当你想要一个视图中的手势识别器前接收触摸。但是,在此之前,你可以改变触摸到的意见传递路径,你需要了解的默认行为。在简单情况下,当发生触摸时,触摸对象从传递的UIApplication对象到一个UIWindow对象。然后,窗口首先发送润色连接,其中接触发生(或该视图的superviews)视图中的任何手势识别器,它通过触摸视图对象本身之前。
这里写图片描述
图1-5 触摸事件的默认传递路径

手势识别器获得的第一次机会来识别触摸

一个窗口延迟到视图递送触摸对象的,使得手势识别可以首先分析的触感。在延时期间,如果手势识别器识别的触摸手势,则窗口从未提供了触摸对象的观点,并且也可以抵消任何触摸物体先前发送到人,承认序列的一部分的观点。

例如,如果有对离散手势,需要一个两指触摸手势识别,这转化为两个独立的触摸物体。作为触摸发生,触摸对象从应用对象为其中触摸发生视图窗口对象传递,并出现以下顺序,如在描绘的图1-6。
这里写图片描述
图1-6 为触摸序列的消息

影响视图触摸点的传递路径

您可以更改几个值UIGestureRecognizer 性质改变在某些方面默认的传递路径。如果更改这些属性的默认值,你的行为有以下区别:

delaysTouchesBegan(默认NO)-Normally,窗口发来的开始,搬到阶段视图和手势识别触摸对象。设置delaysTouc
hesBegan到YES阻止窗口从开始阶段提供触摸对象的视图。这确保当手势识别承认其姿态,没有触摸事件的一部分被传递到附图。设置此属性时,因为它可以让你的界面感觉反应迟钝谨慎。
此设置提供了一个类似的行为的delaysContentTouches财产UIScrollView的 ; 在这种情况下,滚动时开始触摸开始时,滚动视图对象的子视图从不接收在触摸后不久,所以不存在的视觉反馈闪光。

delaysTouchesEnded(默认是) -当这个属性设置为YES,它可以确保一个视图没有完成。这个动作可能要以后取消操作。当手势识别正在分析触摸事件,窗口不会在端相连接的视图提供触摸对象。如果一个手势识别承认其手势,触摸物体被取消。如果手势识别不承认它的姿态,窗这些对象提供通过一个视图touchesEnded:withEvent:方法的消息。此属性设置为NO允许来分析端相接触的物体在同一时间作为手势识别的看法。
考虑,例如,一个视图有一个需要两个抽头的抽头手势识别,并且用户双敲击图。随着属性设置为YES时,视图获得的touchesBegan:withEvent:方法,的touchesBegan:withEvent:方法,touchesCancelled:withEvent:方法和touchesCancelled:withEvent:方法。如果此属性设置为NO,视图中获取消息的顺序如下:的touchesBegan:withEvent:方法,touchesEnded:withEvent:方法,的touchesBegan:withEvent:方法和touchesCancelled:withEvent:方法,这意味着在的touchesBegan:withEvent:方法,视图可以识别双击。

如果一个手势识别检测到的接触,它确定不是其手势的一部分,它可以直接通过触摸其视图。要做到这一点,手势识别来电ignoreTouch:forEvent:本身,通过在触摸对象。

创建自定义手势识别

要实现自定义手势识别,首先创建一个子类的UIGestureRecognizer在Xcode。然后,添加下列导入指令在你的子类的头文件:

接下来,从下面的方法声明复制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;
这些方法具有完全相同的签名和行为相应的触摸事件处理前面所述方法的应用会收到触摸屏在触摸处理方法。在所有你覆盖的方法,你必须调用父类的实现,即使该方法有一个空的实现。

请注意,状态 属性中UIGestureRecognizerSubclass.h现在读写,而不是只读的,因为它是在UIGestureRecognizer.h。子类通过分配改变其状态UIGestureRecognizerState常量该属性。

为实现自定义手势识别的触摸事件处理方法

自定义手势识别实施的心脏是四种方法:的touchesBegan:withEvent:方法,touchesMoved:withEvent:方法,touchesEnded:withEvent:方法和touchesCancelled:withEvent:方法。在这些方法中,通过设置一个手势识别的状态转化低级触摸事件,将手势识别。清单1-8创建一个独立的单点触摸标记姿势手势识别。它记录在其上冲程开始-以便客户端可以获取此值的手势的点的中点。

这个例子只有一个视图,但大多数应用程序有很多的意见。一般情况下,你应该触摸位置转换为屏幕上的坐标系统,这样就可以正确识别跨越多个视图手势。

清单1-8 勾选手势识别的实现

#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;
}

离散和连续的手势状态转换是不同的,如描述手势识别的有限状态机操作。当您创建一个自定义的手势识别,就表明它是否是通过设定相关国家离散或连续。作为一个例子,在复选标记手势识别上市1-8不落的状态开始或更改,因为它是离散的。

你需要继承一个手势识别时做的最重要的事情是设置手势识别的状态准确。的iOS需要知道为了手势识别交互如预期一个手势识别的状态。例如,如果你想允许同时承认或需要手势识别失败,iOS的需要了解你的识别器的当前状态。

欲了解更多有关创建自定义的手势识别,请参阅WWDC 2012:建立先进的手势识别。

重置手势识别的状态

如果你的手势识别过渡到认可/结束,取消或失败时,UIGestureRecognizer类调用复位只是手势识别转换回之前的可能方法。

实施复位方法重置所有内部状态,使您的识别准备在识别一个手势一个新的尝试,如清单1-9。经过手势识别从这个方法返回,它收到正在进行的接触没有进一步的更新。

清单1-9 重置手势识别

- (void)reset {
    [super reset];
    self.midPoint = CGPointZero;
    self.strokeUp = NO;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值