手势UIGestureRecognizer

来源:互联网 发布:linux查看网口状态 编辑:程序博客网 时间:2024/05/03 18:25

UIGestureRecognizer 是识别手势类的抽象基类。

UIGestureRecognizer 有以下子类:

  • UITapGestureRecognizer

  • UIPinchGestureRecognizer

  • UIRotationGestureRecognizer

  • UISwipeGestureRecognizer

  • UIPanGestureRecognizer

  • UIScreenEdgePanGestureRecognizer

  • UILongPressGestureRecognizer

  • 上面的手势对应的操作是: 
    • Tap(点一下)
    • Pinch(二指往內或往外拨动,平时经常用到的缩放)
    • Rotation(旋转)
    • Swipe(滑动,快速移动)
    • Pan (拖移,慢速移动)
    • ScreenEdgePan(屏蔽边缘)
    •  LongPress(长按)

  • 通过内置的手势识别器来处理一个手势的基本流程如下所示:

  • 1.创建一个具有正确类型的对象,作为想要实现的手势识别器;

  • 2.把该对象作为手势识别器添加到需要接收手势的视图中;

  • 3.书写一个方法,该方法当手势事件发生时被调用,由其来执行应用所需的动作。

  • 一般,Tap、pinch,pan、swipe只是一个简单的单个触摸,它有一定的局限性,所以多点触摸诞生了~为实现多点触摸,首先得做下列事情:

    1.设置view的属性multipleTouchEnabled = YES(注意了。。。默认值是NO);
    2.使用CFDictionaryRef来保存触摸过程的参数 。

  • UIControl子类会覆盖parentView的gesture。例如当用户点击UIButton时,UIButton会接受触摸事件,它的parentView不会接收到。

UIGestureRecognizer 类定义了一组常用的方法可用于所有具体的手势识别。也可以和代理(UIGestureRecognizerDelegate协议)实现一些行为。每一个特定的手势必须关联到view对象中才会有作用,一个view对象可以关联多个不同的特定手势,但是每一个特定的手势只能与一个view相关联。当用户触摸了view,这个GestureRecognizer就会接受到消息,它可以响应特定的触摸事件。使用addGestureRecognizer函数来将手势和view对象关联起来,例如:

[snakeImageView addGestureRecognizer:panGestureRecognizer];


初始化一个手势类别:

1.初始化:

- (instancetype)initWithTarget:(id)target                        action:(SEL)action
例如:

    UIImageView *snakeImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"snake.png"]];    snakeImageView.frame = CGRectMake(50, 50, 100, 160);    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc]                                                    initWithTarget:self                                                    action:@selector(handlePan:)];        [snakeImageView addGestureRecognizer:panGestureRecognizer];    [self.view setBackgroundColor:[UIColor whiteColor]];    [self.view addSubview:snakeImageView];
初始化一个Pan拖动手势手势,并添加到UIImageView视图上,并创建回调方法:

- (void) handlePan:(UIPanGestureRecognizer*) recognizer{    //......}
一个方法,若其作为目标方法被绑定到手势识别器中,,它需要遵循下面的规则:

(1).必须返回void

(2).要么不接收任何参数,要么接收一个类型为UIGestureRecogonizer的参数,系统使用这个参数向该方法传递调用该方法的手势识别器


如下:

- (void)handleGesture;- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer;

添加、移除手势的目标和行为方法:

2.添加方法:

- (void)addTarget:(id)target           action:(SEL)action
你可以多次调用这个方法为目标手势添加方法。如果目标重复添加,请求消息被忽略。


3.移除手势识别器的指定方法:

- (void)removeTarget:(id)target              action:(SEL)action



获取触摸发生手势的位置:

4.返回一个给定视图发生手势的点:

- (CGPoint)locationInView:(UIView *)view
返回在视图识别手势的位置的局部坐标系统(响应者坐标系统)的一个点(CGPoint)。如果没有指定视图(nil),该方法返回基于窗口坐标系统的发生手势的点(CGPoint)。

返回的点通常是手势的触摸中心。

5.返回一个给定视图发生手势的点(为了在多个手势中捕获位置):

- (CGPoint)locationOfTouch:(NSUInteger)touchIndex                    inView:(UIView *)view
touchIndex是UITouch对象的私有数组索引。

6.触摸点的个数:

- (NSUInteger)numberOfTouches



要识别的状态和视图:

7.手势状态:

@property(nonatomic, readonly) UIGestureRecognizerState state

8.触发手势的视图(一般在触摸执行操作中我们可以通过此属性获得触摸视图进行操作):

@property(nonatomic, readonly) UIView *view

9.手势是否可用:

@property(nonatomic, getter=isEnabled) BOOL enabled

取消和延迟触动:

10.解除View上的绑定的剩余手势事件:

@property(nonatomic) BOOL cancelsTouchesInView

如果Recognizer分析成功,就会解除View上的绑定的剩余手势事件,那么windows也不会给发送这写手势事件。windows通过给view发送touchesCancelled:withEvent:消息来退出旧事件处理。

cancelsTouchesInView默认为YES,表示当Gesture Recognizers识别到手势后,会向hit-test view发送 touchesCancelled:withEvent:消息来取消hit-test view对此触摸序列的处理,这样只有Gesture Recognizers能响应此触摸序列,hit-test view不再响应。如果为NO,则不发送touchesCancelled:withEvent:消息给hit-test view,这样会使Gesture Recognizers和hit-test view同时响应触摸序列。


11.如果Recognizer分析成功,就不会给View发送手势事件对象( UITouchPhaseBegan),如果失败才会发送:

@property(nonatomic) BOOL delaysTouchesBegan

delaysTouchesBegan默认为NO,表示触摸序列开始时,而手势识别器还未识别出此手势时,touch事件会同时发向hit-test view,这样在手势识别器还未识别出此手势,hit-test view同时也可以收到同样的触摸事件。如果为YES,则在手势识别器在识别手势的过程中,不会有任何触摸事件发送给hit-test view,如果手势识别器最终识别到了手势,则也不会发送任何消息(包括touchesCancelled:withEvent:)给hit-test view;若干手势识别最终没有识别到手势,则所有的触摸事件在发给hit-test view处理。关于这个特性,可参考UIScrollView的delaysContentTouches属性。这样属性也谨慎使用,使用不当会导致UI无响应。


12.如果分析成功,就不会给View发送手势事件对象:

@property(nonatomic) BOOL delaysTouchesEnded
如果分析成功,就不会给View发送手势事件对象( UITouchPhaseEnded),但是会发送touchesCancelled:withEvent消息,如果失败才发送 touchesEnded:withEvent:。默认是YES。
delaysTouchesEnded,在文档上的解释是,当手势识别器在识别手势时,对于UITouchPhaseEnded阶段的touch会延迟发送给hit-test view,在手势识别成功后,发送给hit-test view cancel消息,手势识别失败时,发送原来的end消息。其给出了了这样的例子识别双击操作的UITapGestureRecognizer对象,其numberOfTapsRequired设为2,在用户进行双击操作时,如果delaysTouchesEnded为NO,则hit-test view中的调用序列为
touchesBegan:withEvent:,
touchesEnded:withEvent:,
touchesBegan:withEvent:,
and touchesCancelled:withEvent:
如果delaysTouchesEnded为YES,则调用序列为:
touchesBegan:withEvent:,
touchesBegan:withEvent:,
touchesCancelled:withEvent:,
touchesCancelled:withEvent:
但我在实际测试时,并非如此,实际测试的结果是,如果delaysTouchesEnded为NO,则调用序列为:
touchesBegan:withEvent:,
touchesEnded:withEvent:,
TapGestureRecognizer 检测到双击

如果delaysTouchesEnded为YES,则调用序列为:
touchesBegan:withEvent:,
touchesEnded:withEvent:,
TapGestureRecognizer 检测到双击

touchesCancelled:withEvent:


指定的依赖关系间的手势识别:

13.指定一个手势需要另一个手势失败才能执行:

- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer
例如:

// 如果双击确定偵測失败才會触发单击    [singleRecognizer requireGestureRecognizerToFail:doubleRecognizer];

设置和获取代理:

14.手势代理:

@property(nonatomic, assign) id< UIGestureRecognizerDelegate > delegate


子类方法:

15.一根或多根手指开始触摸屏幕时执行:

- (void)touchesBegan:(NSSet *)touches           withEvent:(UIEvent *)event

16.一根或多根手指在屏幕上移动时执行,注意此方法在移动过程中会重复调用:

- (void)touchesMoved:(NSSet *)touches           withEvent:(UIEvent *)event

17.一根或多根手指触摸结束离开屏幕时执行:

- (void)touchesEnded:(NSSet *)touches           withEvent:(UIEvent *)event

18.触摸意外取消时执行(例如正在触摸时打入电话):
- (void)touchesCancelled:(NSSet *)touches               withEvent:(UIEvent *)event

19.手势结束时重写此方法重置内部状态:

- (void)reset

20.忽略一个特定的事件:

- (void)ignoreTouch:(UITouch *)touch           forEvent:(UIEvent *)event

21.重写显示指定的手势识别器可以防止接收识别手势:

- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer

22.防止从指定手势接收器接收别的手势:

- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer

想控制两个识别器相互作用,但你需要指定一个单向关系,您可以重写或canPreventGestureRecognizer:或canBePreventedByGestureRecognizer:子类方法。return yes。例如,如果你想要一个旋转的姿态来防止捏动作,但你不想夹手势防止旋转的姿态。例如,你想一个旋转手势阻止一个缩放手势,但你不想一个缩放手势阻止旋转手势,就加入下面代码:

[rotationGestureRecognizer canPreventGestureRecognizer:pinchGestureRecognizer];

23.

- (BOOL)shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer

24.

- (BOOL)shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer

数据类型:

25.手势识别状态:

typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {    UIGestureRecognizerStatePossible,   // 尚未识别是何种手势操作(但可能已经触发了触摸事件),默认状态        UIGestureRecognizerStateBegan,      // 手势已经开始,此时已经被识别,但是这个过程中可能发生变化,手势操作尚未完成    UIGestureRecognizerStateChanged,    // 手势状态发生转变    UIGestureRecognizerStateEnded,      // 手势识别操作完成(此时已经松开手指)    UIGestureRecognizerStateCancelled,  // 手势被取消,恢复到默认状态        UIGestureRecognizerStateFailed,     // 手势识别失败,恢复到默认状态        UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded // 手势识别完成,同UIGestureRecognizerStateEnded};


状态转换离散/连续的手势:




iOS的手势识别模型其实是一个状态机
所有手势识别从一个可能状态(UIGestureRecognizerStatePossible)开始,然后开始分析、识别手势,如果识别失败将会进入失败状态 (UIGestureRecognizerStateFailed)。
如果识别成功,进入成功状态(UIGestureRecognizerStateRecognized)
对于连续性的手势,手势识别从Possible进入Began(UIGestureRecognizerStateBegan) ,然后会进入Change (UIGestureRecognizerStateChanged)状态,并在Change状态循环,在最后用户手指离开屏幕的时候会进入End(UIGestureRecognizerStateEnded)状态
连续手势也会从Change进入cancel (UIGestureRecognizerStateCancelled),如果判断手势已经不符合该要求了。
每次Gesture recognizer改变状态的时候都会发送一个action message到target,知道Failed或者Cancel。
有时候会出现iOS判断该手势符合多个条件,而用户此时只想要其中一种,这个情况下可以调用 requireGestureRecognizerToFail: ,该方法会让当前手势对象根据指定对象状态来进行下一步操作。如果指定对象进入Begin状态,当前对象直接进入Failed;如果指定对象进入Failed或Cancel状态,当前对象会进入Begin状态。这里就涉及到了不同手势之间执行的问题。(如果想要单击和双击都要执行,并分别执行不同的逻辑,这里可以先让单机等待双击失败在执行,但这样会导致单击事件稍微延迟执行,因为单击事件需要等待双击事件失败)。
可以选择不让接收、分析手势事件,通过 gestureRecognizer:shouldReceiveTouch: 在最开始的时候允许、拒绝接收手势时间;如果想延后判断则可以通过 gestureRecognizerShouldBegin:,如果返回No则会导致Failed时间
如果想要同时接收两个事件,就调用gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: 默认这个方法返回No,返回Yes则运行同时运行
单向影响,事件A和B, 如果想要让A影响B,但不想让B影响A,则可以通过重载方法 canPreventGestureRecognizer: 或者canBePreventedByGestureRecognizer:实现,比如
[rotationGestureRecognizer canPreventGestureRecognizer:pinchGestureRecognizer];
Touch事件传递过程是上到下,也就是从App->Window->View的过程
Touch事件,window会让Gesture recognizer优先分析touch对象,如果Gesture recognizer成功识别这些对象,touch事件就不会执行。总结就是Gesture recognizer的优先级会低于touch事件
影响touch传递给views
delaysTouchesBegan 阻止在Begin阶段Windows交付touch事件
delaysTouchesEnded Window不会在Enable阶段交付Touch事件
Gesture Recognizer是iOS定制的一些Touch事件类型,Dev可以订制自己的Gesture Recognizer,这里要继承UIGestureRecognizer并覆盖主要的四个类。


子类:

UILongPressGestureRecognizer(长按)

配置手势:

1.最少持续多少秒手势才回被识别:

@property(nonatomic) CFTimeInterval minimumPressDuration
该属性表明用户需要在屏幕上按多长时间才可以触发手势识别事件,以秒为单位。


2.屏幕上必须出现的手指数量:

@property(nonatomic) NSUInteger numberOfTouchesRequired

该属性是指需要多少根手指触碰屏幕才可以触发手势识别。如果numberOfTapsRequired属性设置的值大于0,则你的必须要指定相同数目的手指来检测点击。


3.点击多少次才可以触发手势识别:

@property(nonatomic) NSUInteger numberOfTapsRequired
该属性用以确定用户需要在目标视图上点击的次数,才可以触发手势识别。请记住,点击不仅仅是手指放在屏幕上。一次点击是指将手指放到屏幕上,然后再抬起手指的整个运动过程。该属性的默认值为0。


4.在手势识别取消之前,手指可以在屏幕上移过的最大像素数:

@property(nonatomic) CGFloat allowableMovement
手指按下后事件响应前允许手指移动的偏移量


UIPanGestureRecognizer(拖移,慢速移动)

配置手势:

1.最大/小几根手指可激活拖动手势识别器:

@property(nonatomic) NSUInteger maximumNumberOfTouches
@property(nonatomic) NSUInteger minimumNumberOfTouches

跟踪手势的位置和速度:

1.拖移手势在指定视图中的坐标系统的转换:

- (CGPoint)translationInView:(UIView *)view

2.在指定的视图中的坐标系统中设定转换值:

- (void)setTranslation:(CGPoint)translation                inView:(UIView *)view

3.获得手势速度:

- (CGPoint)velocityInView:(UIView *)view




UIPinchGestureRecognizer(二指往內或往外拨动,平时经常用到的缩放)
解释挤捏手势:
1.根据用户的手势,应该将GUI元素的x轴和y轴缩放的因子:
@property(nonatomic) CGFloat scale

2.挤捏的速度,以多少像素每秒为单位:
@property(nonatomic, readonly) CGFloat velocity
当出点彼此接近时,该速度为负值,而当触点彼此远离时,该速度为正值。



UIRotationGestureRecognizer(旋转)

理解手势:

1.使用弧度单位来定义用户手势的旋转总量以及方向:

@property(nonatomic) CGFloat rotation
旋转有手指的初始位置(UIRotationGestureRecognizerStateBegan)以及最终位置(UIRotationGestureRecognizerStateEnded)来决定。

2.旋转的速度:

@property(nonatomic, readonly) CGFloat velocity




UISwipeGestureRecognizer(滑动,快速移动)

配置手势:

1.方向控制:

@property(nonatomic) UISwipeGestureRecognizerDirection direction
默认的方向是uiswipegesturerecognizerdirectionright。更多信息见uiswipegesturerecognizerdirection类型常数描述

2.屏幕上必须出现的手指数量:

@property(nonatomic) NSUInteger numberOfTouchesRequired

该属性是指需要多少根手指触碰屏幕才可以触发手势识别。如果numberOfTapsRequired属性设置的值大于0,则你的必须要指定相同数目的手指来检测点击。

数据类型:

3.方向:

typedef enum {   UISwipeGestureRecognizerDirectionRight = 1 << 0,   UISwipeGestureRecognizerDirectionLeft  = 1 << 1,   UISwipeGestureRecognizerDirectionUp    = 1 << 2,   UISwipeGestureRecognizerDirectionDown  = 1 << 3} UISwipeGestureRecognizerDirection;

UITapGestureRecognizer(点一下)

配置手势:

1.

点击多少次才可以触发手势识别:

@property(nonatomic) NSUInteger numberOfTapsRequired
该属性用以确定用户需要在目标视图上点击的次数,才可以触发手势识别。请记住,点击不仅仅是手指放在屏幕上。一次点击是指将手指放到屏幕上,然后再抬起手指的整个运动过程。该属性的默认值为0。

0 0
原创粉丝点击