手势识别(四)多手势间的交互与共存

Defining How Gesture Recognizers Interact

四、定义手势识别如何交互

Oftentimes, as you add gesture recognizers to your app, you need to be specific about how you want the recognizers to interact with each other or any other touch-event handling code in your app. To do this, you first need to understand a little more about how gesture recognizers work.

通常情况下,当你把手势识别添加到应用程序时,你需要了解你想要你的识别(recognizers)之间如何发生交互,或者跟应用程序的其它任何触摸事件处理代码如何发生交互。要想完成这些,你首先需要理解更多点关于手势识别如何工作的知识。

Gesture Recognizers Operate in a Finite State Machine

1、手势识别在一个有限状态机里操作

Gesture recognizers transition from one state to another in a predefined way. From each state, they can move to one of several possible next states based on whether they meet certain conditions. The exact state machine varies depending on whether the gesture recognizer is discrete or continuous, as illustrated inFigure 1-3. All gesture recognizers start in the Possible state (UIGestureRecognizerStatePossible). They analyze any multitouch sequences that they receive, and during analysis they either recognize or fail to recognize a gesture. Failing to recognize a gesture means the gesture recognizer transitions to the Failed state (UIGestureRecognizerStateFailed).

手势识别以一种预定义的方式从一个状态过渡到另一个状态。 每种状态都可以根据它们遇到的特定条件(conditions)过渡到几种可能的未来状态中的一种。确切的状态机根据手势识别是离散或是连续会发生变化,正如图1-3中所示。所有的手势识别在一个可能的状态(UIGestureRecognizerStatePossible)中开始, 它们分析接收到的任何多点触摸序列,并且在分析过程中成功识别手势或者识别识别一个手势。失败识别手势意味着手势识别过渡到失败状态     (UIGestureRecognizerStateFailed).

Figure 1-3  State machines for gesture recognizers

图1-3 手势识别的状态机

When a discrete gesture recognizer recognizes its gesture, the gesture recognizer transitions from Possible to Recognized (UIGestureRecognizerStateRecognized) and the recognition is complete.

当一个离散手势识别识别出它的手势,手势识别从可能状态过渡到被识别状态  (UIGestureRecognizerStateRecognized) , 然后识别完成。

For continuous gestures, the gesture recognizer transitions from Possible to Began (UIGestureRecognizerStateBegan) when the gesture is first recognized. Then, it transitions from Began to Changed (UIGestureRecognizerStateChanged), and continues to move from Changed to Changed as the gesture occurs. When the user’s last finger is lifted from the view, the gesture recognizer transitions to the Ended state (UIGestureRecognizerStateEnded) and the recognition is complete. Note that the Ended state is an alias for the Recognized state.

对于连续手势,当手势第一次被识别时,手势识别从可能状态开始(UIGestureRecognizerStateBegan)。然后,它从开始状态过渡到改变状态(UIGestureRecognizerStateChanged), 然后当手势发生时又从改变状态变为改变状态。 当用户的最后一个手指从视图上举起时,手势识别过渡到结束状态(UIGestureRecognizerStateEnded), 识别完成。 注意结束状态是识别完成状态的一个别名。

A recognizer for a continuous gesture can also transition from Changed to Canceled (UIGestureRecognizerStateCancelled) if it decides that the gesture no longer fits the expected pattern.

如果一个连续手势不再适应预期的模式时,它的识别还可以从改变状态过渡到取消状态(UIGestureRecognizerStateCancelled)。

Every time a gesture recognizer changes state, the gesture recognizer sends an action message to its target, unless it transitions to Failed or Canceled. Thus, a discrete gesture recognizer sends only a single action message when it transitions from Possible to Recognized. A continuous gesture recognizer sends many action messages as it changes states.

每次手势识别改变状态时,手势识别都给它的目标发送一个操作消息,除非它过渡到失败或取消状态。 然而,一个离散手势识别只在它从可能状态过渡到被识别状态时才发送一个单个操作消息。一个连续手势识别在状态发生改变时发送多个操作消息。

When a gesture recognizer reaches the Recognized (or Ended) state, it resets its state back to Possible. The transition back to Possible does not trigger an action message.

当一个手势识别到达被识别(或结束)状态时,它把状态重置为可能(Possible)状态。把状态重置为可能状态不会触发一个操作消息。

Interacting with Other Gesture Recognizers

2、跟其它手势识别发生交互

A view can have more than one gesture recognizer attached to it. Use the view’s gestureRecognizers property to determine what gesture recognizers are attached to a view. You can also dynamically change how a view handles gestures by adding or removing a gesture recognizer from a view with theaddGestureRecognizer: and removeGestureRecognizer: methods, respectively.

一个视图可以带有多个手势。使用视图的gestureRecognizers 特性来确定视图都带有哪些手势识别。 你还可以分别(respectively)使用addGestureRecognizer: 方法和removeGestureRecognizer: 方法添加和删除视图上的手势识别来动态改变视图如何处理手势。

When a view has multiple gesture recognizers attached to it, you may want to alter how the competing gesture recognizers receive and analyze touch events. By default, there is no set order for which gesture recognizers receive a touch first, and for this reason touches can be passed to gesture recognizers in a different order each time. You can override this default behavior to:

当视图带有多个手势识别时,你可能想要改变竞争(competing)手势识别是如何接收和分析触摸事件。默认情况下,没有设置哪个手势识别首先接收到第一个触摸,因此每次触摸都可以以不同的顺序传送给手势识别。 你可以重写该默认行为来:

  • Specify that one gesture recognizer should analyze a touch before another gesture recognizer.

  • 指定一个手势识别应该比另一个手势识别优先分析某个触摸。
  • Allow two gesture recognizers to operate simultaneously.

  • 允许两个手势识别来同时操作
  • Prevent a gesture recognizer from analyzing a touch.

  • 阻止某个手势识别分析某个触摸

Use the UIGestureRecognizer class methods, delegate methods, and methods overridden by subclasses to effect these behaviors.

使用UIGestureRecognizer 类方法,委托方法,以及其子类重写的方法来影响这些行为。

Declaring a Specific Order for Two Gesture Recognizers

1)为两个手势识别声明一个特定顺序

Imagine that you want to recognize a swipe and a pan gesture, and you want these two gestures to trigger distinct actions. By default, when the user attempts to swipe, the gesture is interpreted as a pan. This is because a swiping gesture meets the necessary conditions to be interpreted as a pan (a continuous gesture) before it meets the necessary conditions to be interpreted as a swipe (a discrete gesture).

想象一下,你想要识别一个快速滑动(swipe)和一个慢速拖动(pan)手势,你想要用这两个手势触发不同的操作。默认情况下,当用户尝试swipe时,该手势会被理解为一个pan。 这是因为swipe(一个离散手势)手势在满足各种必要条件被理解为一个swipe手势之前,首先满足pan(一个连续手势)手势的各种必要条件。

For your view to recognize both swipes and pans, you want the swipe gesture recognizer to analyze the touch event before the pan gesture recognizer does. If the swipe gesture recognizer determines that a touch is a swipe, the pan gesture recognizer never needs to analyze the touch. If the swipe gesture recognizer determines that the touch is not a swipe, it moves to the Failed state and the pan gesture recognizer should begin analyzing the touch event.

要想视图同时识别swipes 和pans,你想要swipe手势识别在pan手势之前来分析触摸事件。 如果swipe手势识别已经确定某个触摸是一个swipe, 那么pan手势识别就绝没有必要再去分析该触摸。 如果swipe手势识别确定该触摸不是一个swipe, 它过渡到Failed状态,然后pan手势识别应该开始分析该触摸事件。

You indicate this type of relationship between two gesture recognizers by calling the requireGestureRecognizerToFail: method on the gesture recognizer that you want to delay, as in Listing 1-6. In this listing, both gesture recognizers are attached to the same view.

你可以通过调用手势识别的requireGestureRecognizerToFail: 方法来说明两个手势识别之间这种类型的关系,如列表1-6所示。在该列表中,两个手势识别都被连接到了相同的视图上。

Listing 1-6  Pan gesture recognizer requires a swipe gesture recognizer to fail

列表1-6 pan手势识别要求swipe手势识别到达fail状态

- (void)viewDidLoad {
       [super viewDidLoad];
       // Do any additional setup after loading the view, typically from a nib
       [self.panRecognizer requireGestureRecognizerToFail:self.swipeRecognizer];
}

The requireGestureRecognizerToFail: method sends a message to the receiver and specifies some otherGestureRecognizer that must fail before the receiving recognizer can begin. While it’s waiting for the other gesture recognizer to transition to the Failed state, the receiving recognizer stays in the Possible state. If the other gesture recognizer fails, the receiving recognizer analyzes the touch event and moves to its next state. On the other hand, if the other gesture recognizer transitions to Recognized or Began, the receiving recognizer moves to the Failed state. For information about state transitions, see “Gesture Recognizers Operate in a Finite State Machine.”

requireGestureRecognizerToFail: 方法给接收者发送了一个消息,并且指定了一些otherGestureRecognizer,它们必须在接收识别(receiving recognizer)开始工作之前进入Failed 状态当它等待其它手势识别过渡到Failed状态期间,接收识别(receiving recognizer)始终处于Possible状态。如果其它手势识别失败了,receiving recognizer 开始分析触摸事件并移动到下个状态。换句话说,如果其它手势识别过渡到Recognized 或者 Began状态,receiving recognizer就移动到Failed 状态。 关于状态过渡的更多信息, 请看“Gesture Recognizers Operate in a Finite State Machine.”

Note: If your app recognizes both single and double taps and your single tap gesture recognizer does not require the double tap recognizer to fail, then you should expect to receive single tap actions before double tap actions, even when the user double taps. This behavior is intentional because the best user experience generally enables multiple types of actions.

注意:如果你的应用程序识别同时支持单击和双击,并且你的单击手势识别不要求双击识别失败,那么即使是用户双击时,你也应该期待在双击操作之前接收单击操作。该行为是有意设计的,因为最好的用户体验通常都开启多种类型的操作。

If you want these two actions to be mutually exclusive, your single tap recognizer must require the double tap recognizer to fail. However, your single tap actions will lag a little behind the user’s input because the single tap recognizer is delayed until the double tap recognizer fails.

 如果你想要这两种操作不兼容,你的单击识别必须要求双击识别进入失败状态。 然而,这样你的单击操作会滞后用户的输入,因为单击识别会等到双击识别失败后才开始识别。

Preventing Gesture Recognizers from Analyzing Touches

2)阻止手势识别分析触摸

You can alter the behavior of a gesture recognizer by adding a delegate object to your gesture recognizer. The UIGestureRecognizerDelegate protocol provides a couple of ways that you can prevent a gesture recognizer from analyzing touches. You use either the gestureRecognizer:shouldReceiveTouch: method or the gestureRecognizerShouldBegin: method—both are optional methods of the UIGestureRecognizerDelegate protocol.

你可以通过添加一个委托对象到手势识别来改变手势识别的行为。UIGestureRecognizerDelegate 协议提供了一组方法来阻止手势识别分析触摸。 你可以选择使用协议中的 gestureRecognizer:shouldReceiveTouch: 方法 和  gestureRecognizerShouldBegin: 方法中的一个来使用。

When a touch begins, if you can immediately determine whether or not your gesture recognizer should consider that touch, use thegestureRecognizer:shouldReceiveTouch: method. This method is called every time there is a new touch. Returning NO prevents the gesture recognizer from being notified that a touch occurred. The default value is YES. This method does not alter the state of the gesture recognizer.

当一个触摸开始时,如果你可以立即确定手势识别是否应该考虑该触摸,使用 gestureRecognizer:shouldReceiveTouch: 方法来实现。每次有新触摸时都调用该方法。 阻止手势识别注意到一个触摸的发生,请返回NO。默认值是YES。该方法不改变手势识别的状态。

Listing 1-7 uses the gestureRecognizer:shouldReceiveTouch: delegate method to prevent a tap gesture recognizer from receiving touches that are within a custom subview. When a touch occurs, the gestureRecognizer:shouldReceiveTouch: method is called. It determines whether the user touched the custom view, and if so, prevents the tap gesture recognizer from receiving the touch event.

列表1-7 使用 gestureRecognizer:shouldReceiveTouch: 委托方法来阻止手势识别接收到来自一个自定义子视图中发生的触摸。

Listing 1-7  Preventing a gesture recognizer from receiving a touch

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

If you need to wait as long as possible before deciding whether or not a gesture recognizer should analyze a touch, use the gestureRecognizerShouldBegin:delegate method. Generally, you use this method if you have a UIView or UIControl subclass with custom touch-event handling that competes with a gesture recognizer. Returning NO causes the gesture recognizer to immediately fail, which allows the other touch handling to proceed. This method is called when a gesture recognizer attempts to transition out of the Possible state, if the gesture recognition would prevent a view or control from receiving a touch.

如果你需要在确定手势识别是否应该分析一个触摸之前一直等待。使用 gestureRecognizerShouldBegin: 委托方法。 通常,如果你有一个UIView 或 UIControl子类并带有跟手势识别想冲突的自定义触摸事件处理,你可以使用该方法。返回NO,让手势识别立即进入失败状态,允许其他触摸处理来处理。 当手势识别想要过渡到Possible状态以外的状态时,如果手势识别将阻止一个视图或控件接收一个触摸,该方法被调用。

You can use the gestureRecognizerShouldBegin:UIView method if your view or view controller cannot be the gesture recognizer’s delegate. The method signature and implementation is the same.

如果你的视图或视图控制器不能成为手势识别委托,你可以使用UIView的fgestureRecognizerShouldBegin:方法 。该方法的签名和实现是一样的。

Permitting Simultaneous Gesture Recognition

3)开启同时手势识别

By default, two gesture recognizers cannot recognize their respective gestures at the same time. But suppose, for example, that you want the user to be able to pinch and rotate a view at the same time. You need to change the default behavior by implementing thegestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: method, an optional method of the UIGestureRecognizerDelegateprotocol. This method is called when one gesture recognizer’s analysis of a gesture would block another gesture recognizer from recognizing its gesture, or vice versa. This method returns NO by default. Return YES when you want two gesture recognizers to analyze their gestures simultaneously.

默认情况下,两个手势识别不能同时识别它们的不同手势。但是,假设你想让用户可以同时捏合并旋转一个视图,你需要改变默认行为,你可以通过调用gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: 方法来实现。该方法是 UIGestureRecognizerDelegate 协议的一个可选方法。 当一个手势识别的手势分析可能阻碍另一个手势识别识别它的手势时可以调用该方法,反之亦然。 该方法默认范围NO。当你想让两个手势同时分析它们的手势时,返回YES。

Note: You need to implement a delegate and return YES on only one of your gesture recognizers to allow simultaneous recognition. However, that also means that returning NO doesn’t necessarily prevent simultaneous recognition because the other gesture recognizer's delegate could return YES.

 注意:你只在一个手势识别需要开启同时识别功能时才需要实现一个委托并返回YES。 然而,它还意味着返回NO并不一定阻止同时识别功能,因为其他手势识别的委托可能返回了YES。

Specifying a One-Way Relationship Between Two Gesture Recognizers

4)给两个手势指定一个单向关系

If you want to control how two recognizers interact with each other but you need to specify a one-way relationship, you can override either thecanPreventGestureRecognizer: or canBePreventedByGestureRecognizer: subclass methods to return NO (default is YES). For example, if you want a rotation gesture to prevent a pinch gesture but you don’t want a pinch gesture to prevent a rotation gesture, you would specify:

如果你想要控制两个识别(recognizers)是如何交互,但是你需要指定一个单向关系,你可以重写canPreventGestureRecognizer: 或 canBePreventedByGestureRecognizer: 子类方法并返回NO(默认为YES)。 比如,如果你想用一个旋转手势阻止一个捏合手势,但是你又不想捏合手势阻止一个旋转手势,你可以用如下语句指定。

[rotationGestureRecognizer canPreventGestureRecognizer:pinchGestureRecognizer];

and override the rotation gesture recognizer’s subclass method to return NO. For more information about how to subclass UIGestureRecognizer, see “Creating a Custom Gesture Recognizer.”

同时,重写旋转手势识别的子类方法来返回NO. 更多管理如何子类化 UIGestureRecognizer的信息,请看 “Creating a Custom Gesture Recognizer.”

If neither gesture should prevent the other, use the gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: method, as described in“Permitting Simultaneous Gesture Recognition.” By default, a pinch gesture prevents a rotation and vice versa because two gestures cannot be recognized at the same time.

如果没有手势需要阻止另外手势,使用gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: ,它在“Permitting Simultaneous Gesture Recognition.” 里描述。 默认情况下,捏合手势阻止旋转手势,或者旋转手势阻止捏合手势,因为两个手势不能同时被识别。

Interacting with Other User Interface Controls

5) 跟别的用户界面控件交互

In iOS 6.0 and later, default control actions prevent overlapping gesture recognizer behavior. For example, the default action for a button is a single tap. If you have a single tap gesture recognizer attached to a button’s parent view, and the user taps the button, then the button’s action method receives the touch event instead of the gesture recognizer. This applies only to gesture recognition that overlaps the default action for a control, which includes:

在iOS 6.0 或以后版本中,默认控件操作方法防止(prevent)重复手势识别的行为。比如,一个按钮的默认操作是一个单击。如果你有一个单击手势识别绑定到一个按钮的父视图上,然后用户点击该按钮,最后按钮的操作方法接收触摸事件而不是手势识别。 它只用于手势识别跟一个控件的默认操作重复时,包括:

If you have a custom subclass of one of these controls and you want to change the default action, attach a gesture recognizer directly to the control instead of to the parent view. Then, the gesture recognizer receives the touch event first. As always, be sure to read the iOS Human Interface Guidelines to ensure that your app offers an intuitive user experience, especially when overriding the default behavior of a standard control.

如果你有一个这些控件的自定义子类,你想要改变其默认操作,把手势识别直接连接到控件而不是连接到其父视图。然后,手势识别首先接收到触摸事件。一如往常,请确保你已经阅读了 iOS Human Interface Guidelines 文档以确保你的应用程序提供了一个直观的用户体验,特别是当你重写一个标准控件的默认行为时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值