首页 > 代码库 > iOS手势处理

iOS手势处理

iOS手势有着如下几种:

  • UITapGestureRecognizer  
  • UIPinchGestureRecognizer
  • UIRotationGestureRecognizer
  • UISwipeGestureRecognizer
  • UIPanGestureRecognizer
  • UILongPressGestureRecognizer

上面的手势对应的操作是: 

  • Tap          (点一下)
  • Pinch        (二指往內或往外拨动,平时经常用到的缩放)  矩阵变换
  • Rotation    (旋转)                                                  矩阵变换
  • Swipe       (滑动,快速移动)
  • Pan          (拖移,慢速移动)                                     矩阵变换
  • LongPress (长按

 

注意:以下示例均把手势封装进一个View当中

UITapGestureRecognizer - 点击手势

GestureView.h + GestureView.m

 GestureView.h
 GestureView.m

- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer

Attaching a gesture recognizer to a view defines the scope of the represented gesture, causing it to receive touches hit-tested to that view and all of its subviews. The view establishes a strong reference to the gesture recognizer.

将手势识别器附着在一个view上,实际上定义了一个手势接收的区域,会将接收到的触摸事件传递给这个view以及这个view的所有的subviews.这个view会对这个手势识别器强引用.

可以总结两点:

1. 手势会传递给这个view中所有的subviews

2. view会强引用手势识别器

使用如下:

点击手势有两个参数可以设置:

numberOfTapsRequired         点击几次触发事件(默认是1)

numberOfTouchesRequired    需要几个手指点击(默认是1)

 

UIPinchGestureRecognizer - 缩放

GestureView.h + GestureView.m

 GestureView.h
 GestureView.m

缩放手势会用到矩阵变换.

 

UIRotationGestureRecognizer - 旋转

GestureView.h + GestureView.m

 GestureView.h
 GestureView.m

 

UISwipeGestureRecognizer - 滑动

GestureView.h + GestureView.m

 GestureView.h
 GestureView.m

 

UIPanGestureRecognizer - 平移

GestureView.h + GestureView.m

 GestureView.h
 GestureView.m

 

UILongPressGestureRecognizer - 长按手势

GestureView.h + GestureView.m

 GestureView.h
 GestureView.m

 

 

问题:如何处理一个view中添加了两个手势,1个是单击的手势,一个是双击的手势呢?

可以使用这个方法requireGestureRecognizerToFail:

 GestureView.m

实际上,这种方式会有延时感-_-!!!!

 

问题:如何将长按手势和拖拽手势合并在一起呢? 

我们需要用代理实现,实现以下的方法:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer  shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer

Asks the delegate if two gesture recognizers should be allowed to recognize gestures simultaneously.

询问这个代理,是否允许两个手势同时触发.

 GestureView.m

根据手势状态来识别手势触发事件的全称细节是十分重要的.

 

问题:如何让一个view的部分区域响应拖拽事件呢? 

比方说,我们只需要下面红色线指定的区域响应拖拽事件:

 GestureView.m

 要实现那个效果,以下方法是核心方法,配合手势的状态使用:

// 获取到当前手势在当前视图坐标中触摸的点
    CGPoint point = [sender locationInView:self];

 

问题:如何在ViewController中获取到点击的坐标,让一个view跟随触摸点移动呢?

可以使用这几个最原始的处理触摸事件的方法来达到效果.

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

 RootViewController.m

也可以直接使用拖拽手势来实现的,不过不完美

 RootViewController.m

他们两者的对比关系:

 

 

手势处理中核心的地方:

1.  UIGestureRecognizerState非常重要,触发事件时可以直接根据这个状态值来判断事件的发生顺序

2.  处理多手势冲突时,可以使用依赖requireGestureRecognizerToFail:来处理,但效果不好

3.  处理多个手势并发响应的时候,需要实现代理并执行方法,请参考上面的事例

4.  仅仅处理一个view上局部的手势事件,需要用到手势的locationInView:方法,并与UIGestureRecognizerState状态值配合使用

 

 

附录:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch

这是手势的代理方法,在可以不移除手势的情况下关闭手势的响应,此方法涉及到响应链.