当前位置: 移动技术网 > IT编程>移动开发>IOS > iOS手势识别的详细使用方法(拖动,缩放,旋转,点击,手势依赖,自定义手势)

iOS手势识别的详细使用方法(拖动,缩放,旋转,点击,手势依赖,自定义手势)

2019年07月24日  | 移动技术网IT编程  | 我要评论

毕业那天我们失业,家n次方全集下载,放不下伴奏

手势识别在ios上非常重要,手势操作移动设备的重要特征,极大的增加了移动设备使用便捷性。

1、uigesturerecognizer介绍

手势识别在ios上非常重要,手势操作移动设备的重要特征,极大的增加了移动设备使用便捷性。

ios系统在3.2以后,为方便开发这使用一些常用的手势,提供了uigesturerecognizer类。手势识别uigesturerecognizer类是个抽象类,下面的子类是具体的手势,开发这可以直接使用这些手势识别。

  • uitapgesturerecognizer 
  • uipinchgesturerecognizer
  • uirotationgesturerecognizer
  • uiswipegesturerecognizer
  • uipangesturerecognizer
  • uilongpressgesturerecognizer

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

  • tap(点一下)
  • pinch(二指往內或往外拨动,平时经常用到的缩放)
  • rotation(旋转)
  • swipe(滑动,快速移动)
  • pan (拖移,慢速移动)
  •  longpress(长按)

uigesturerecognizer的继承关系如下:

2、使用手势的步骤

使用手势很简单,分为两步:

创建手势实例。当创建手势时,指定一个回调方法,当手势开始,改变、或结束时,回调方法被调用。

添加到需要识别的view中。每个手势只对应一个view,当屏幕触摸在view的边界内时,如果手势和预定的一样,那就会回调方法。

ps:一个手势只能对应一个view,但是一个view可以有多个手势。

建议在真机上运行这些手势,模拟器操作不太方便,可能导致你认为手势失效。

3、pan 拖动手势:

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]; 

新建一个imageview,然后添加手势

回调方法:

- (void) handlepan:(uipangesturerecognizer*) recognizer 
{ 
  cgpoint translation = [recognizer translationinview:self.view]; 
  recognizer.view.center = cgpointmake(recognizer.view.center.x + translation.x, 
                  recognizer.view.center.y + translation.y); 
  [recognizer settranslation:cgpointzero inview:self.view]; 
   
} 

4、pinch缩放手势

uipinchgesturerecognizer *pinchgesturerecognizer = [[uipinchgesturerecognizer alloc] 
                            initwithtarget:self 
                            action:@selector(handlepinch:)];<p class="p1">[<span class="s1">snakeimageview</span> <span class="s2">addgesturerecognizer</span>:pinchgesturerecognizer];</p> 
- (void) handlepinch:(uipinchgesturerecognizer*) recognizer 
{ 
  recognizer.view.transform = cgaffinetransformscale(recognizer.view.transform, recognizer.scale, recognizer.scale); 
  recognizer.scale = 1; 
} 

5、rotation旋转手势

uirotationgesturerecognizer *rotaterecognizer = [[uirotationgesturerecognizer alloc] 
                         initwithtarget:self 
                         action:@selector(handlerotate:)]; 
[snakeimageview addgesturerecognizer:rotaterecognizer]; 
- (void) handlerotate:(uirotationgesturerecognizer*) recognizer 
{ 
  recognizer.view.transform = cgaffinetransformrotate(recognizer.view.transform, recognizer.rotation); 
  recognizer.rotation = 0; 
} 

添加了这几个手势后,运行看效果,程序中的imageview放了一个

                   /^\/^\
                  _|__|  o|
         \/     /~     \_/ \
          \____|__________/  \
                 \_______      \
                         `\     \                 \
                           |     |                  \
                          /      /                    \
                         /     /                       \\
                       /      /                         \ \
                      /     /                            \  \
                    /     /             _----_            \   \
                   /     /           _-~      ~-_         |   |
                  (      (        _-~    _--_    ~-_     _/   |
                   \      ~-____-~    _-~    ~-_    ~-_-~    /
                     ~-_           _-~          ~-_       _-~ 
                        ~--______-~                ~-___-~

的图片,在模拟器上拖动是没问题的。缩放和旋转有点问题,估计是因为在模拟器上的模拟的两个接触点距离在imageview的边界外了,所以操作无效果。

建议在真机上运行这个手势。

在模拟器上缩放和选择的操作技巧:

可以把imageview的frame值设置大一点,按住alt键,按下触摸板(不按下不行),这样就可以旋转和缩放了。

6、添加第二个imagview并添加手势

记住:一个手势只能添加到一个view,两个view当然要有两个手势的实例了

- (void)viewdidload 
{ 
  [super viewdidload]; 
 
  uiimageview *snakeimageview = [[uiimageview alloc] initwithimage:[uiimage imagenamed:@"snake.png"]]; 
  uiimageview *dragonimageview = [[uiimageview alloc] initwithimage:[uiimage imagenamed:@"dragon.png"]]; 
  snakeimageview.frame = cgrectmake(120, 120, 100, 160); 
  dragonimageview.frame = cgrectmake(50, 50, 100, 160); 
  [self.view addsubview:snakeimageview]; 
  [self.view addsubview:dragonimageview]; 
   
  for (uiview *view in self.view.subviews) { 
    uipangesturerecognizer *pangesturerecognizer = [[uipangesturerecognizer alloc] 
                            initwithtarget:self 
                            action:@selector(handlepan:)]; 
     
    uipinchgesturerecognizer *pinchgesturerecognizer = [[uipinchgesturerecognizer alloc] 
                              initwithtarget:self 
                              action:@selector(handlepinch:)]; 
     
    uirotationgesturerecognizer *rotaterecognizer = [[uirotationgesturerecognizer alloc] 
                             initwithtarget:self 
                             action:@selector(handlerotate:)]; 
     
    [view addgesturerecognizer:pangesturerecognizer]; 
    [view addgesturerecognizer:pinchgesturerecognizer]; 
    [view addgesturerecognizer:rotaterecognizer]; 
    [view setuserinteractionenabled:yes]; 
  } 
  [self.view setbackgroundcolor:[uicolor whitecolor]];    
} 

多添加了一条龙的view,两个view都能接收上面的三种手势。运行效果如下:

7、拖动(pan手势)速度(以较快的速度拖放后view有滑行的效果)
如何实现呢?

  • 监视手势是否结束
  • 监视触摸的速度
- (void) handlepan:(uipangesturerecognizer*) recognizer 
{ 
  cgpoint translation = [recognizer translationinview:self.view]; 
  recognizer.view.center = cgpointmake(recognizer.view.center.x + translation.x, 
                    recognizer.view.center.y + translation.y); 
  [recognizer settranslation:cgpointzero inview:self.view]; 
   
  if (recognizer.state == uigesturerecognizerstateended) { 
     
    cgpoint velocity = [recognizer velocityinview:self.view]; 
    cgfloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y)); 
    cgfloat slidemult = magnitude / 200; 
    nslog(@"magnitude: %f, slidemult: %f", magnitude, slidemult); 
     
    float slidefactor = 0.1 * slidemult; // increase for more of a slide 
    cgpoint finalpoint = cgpointmake(recognizer.view.center.x + (velocity.x * slidefactor), 
                     recognizer.view.center.y + (velocity.y * slidefactor)); 
    finalpoint.x = min(max(finalpoint.x, 0), self.view.bounds.size.width); 
    finalpoint.y = min(max(finalpoint.y, 0), self.view.bounds.size.height); 
     
    [uiview animatewithduration:slidefactor*2 delay:0 options:uiviewanimationoptioncurveeaseout animations:^{ 
      recognizer.view.center = finalpoint; 
    } completion:nil]; 
     
  } 

代码实现解析:

  • 计算速度向量的长度(估计大部分都忘了)这些知识了。
  • 如果速度向量小于200,那就会得到一个小于的小数,那么滑行会很短
  • 基于速度和速度因素计算一个终点
  • 确保终点不会跑出父view的边界
  • 使用uiview动画使view滑动到终点

运行后,快速拖动图像view放开会看到view还会在原来的方向滑行一段路。

8、同时触发两个view的手势

手势之间是互斥的,如果你想同时触发蛇和龙的view,那么需要实现协议

uigesturerecognizerdelegate,

@interface viewcontroller : uiviewcontroller<uigesturerecognizerdelegate> 
@end 

并在协议这个方法里返回yes。

-(bool)gesturerecognizer:(uigesturerecognizer *)gesturerecognizer shouldrecognizesimultaneouslywithgesturerecognizer:(uigesturerecognizer *)othergesturerecognizer 
{ 
  return yes; 
} 

 把self作为代理设置给手势:

pangesturerecognizer.delegate = self; 
pinchgesturerecognizer.delegate = self; 
rotaterecognizer.delegate = self; 

这样可以同时拖动或旋转缩放两个view了。

9、tap点击手势

这里为了方便看到tap的效果,当点击一下屏幕时,播放一个声音。

为了播放声音,我们加入avfoundation.framework这个框架。

- (avaudioplayer *)loadwav:(nsstring *)filename { 
  nsurl * url = [[nsbundle mainbundle] urlforresource:filename withextension:@"wav"]; 
  nserror * error; 
  avaudioplayer * player = [[avaudioplayer alloc] initwithcontentsofurl:url error:&error]; 
  if (!player) { 
    nslog(@"error loading %@: %@", url, error.localizeddescription); 
  } else { 
    [player preparetoplay]; 
  } 
  return player; 
} 

我会在最后例子代码给出完整代码,添加手势的步骤和前面一样的。

#import <uikit/uikit.h> 
#import <avfoundation/avfoundation.h> 
 
@interface viewcontroller : uiviewcontroller<uigesturerecognizerdelegate> 
@property (strong) avaudioplayer * chompplayer; 
@property (strong) avaudioplayer * heheplayer; 
 
@end 
- (void)handletap:(uitapgesturerecognizer *)recognizer { 
  [self.chompplayer play]; 
} 

运行,点一下某个图,就会播放一个咬东西的声音。

不过这个点击播放声音有点缺陷,就是在慢慢拖动的时候也会播放。这使得两个手势重合了。怎么解决呢?使用手势的:

requiregesturerecognizertofail方法。

10、手势的依赖性

在viewdidload的循环里添加这段代码:

[taprecognizer requiregesturerecognizertofail:pangesturerecognizer]; 

意思就是,当如果pan手势失败,就是没发生拖动,才会出发tap手势。这样如果你有轻微的拖动,那就是pan手势发生了。tap的声音就不会发出来了。

11、自定义手势

自定义手势继承:uigesturerecognizer,实现下面的方法:

– touchesbegan:withevent: 
– touchesmoved:withevent: 
– touchesended:withevent: 
- touchescancelled:withevent: 

新建一个类,继承uigesturerecognizer,代码如下:
.h文件

#import <uikit/uikit.h> 
typedef enum { 
  directionunknown = 0, 
  directionleft, 
  directionright 
} direction; 
 
@interface happygesturerecognizer : uigesturerecognizer 
@property (assign) int ticklecount; 
@property (assign) cgpoint curticklestart; 
@property (assign) direction lastdirection; 
 
@end 

.m文件

#import "happygesturerecognizer.h" 
#import <uikit/uigesturerecognizersubclass.h> 
#define required_tickles    2 
#define move_amt_per_tickle   25 
 
@implementation happygesturerecognizer 
 
- (void)touchesbegan:(nsset *)touches withevent:(uievent *)event { 
  uitouch * touch = [touches anyobject]; 
  self.curticklestart = [touch locationinview:self.view]; 
} 
 
- (void)touchesmoved:(nsset *)touches withevent:(uievent *)event { 
   
  // make sure we've moved a minimum amount since curticklestart 
  uitouch * touch = [touches anyobject]; 
  cgpoint ticklepoint = [touch locationinview:self.view]; 
  cgfloat moveamt = ticklepoint.x - self.curticklestart.x; 
  direction curdirection; 
  if (moveamt < 0) { 
    curdirection = directionleft; 
  } else { 
    curdirection = directionright; 
  } 
  if (abs(moveamt) < move_amt_per_tickle) return; 
   
  // 确认方向改变了 
  if (self.lastdirection == directionunknown || 
    (self.lastdirection == directionleft && curdirection == directionright) || 
    (self.lastdirection == directionright && curdirection == directionleft)) { 
     
    // 挠痒次数 
    self.ticklecount++; 
    self.curticklestart = ticklepoint; 
    self.lastdirection = curdirection; 
     
    // 一旦挠痒次数超过指定数,设置手势为结束状态 
    // 这样回调函数会被调用。 
    if (self.state == uigesturerecognizerstatepossible && self.ticklecount > required_tickles) { 
      [self setstate:uigesturerecognizerstateended]; 
    } 
  } 
   
} 
 
- (void)reset { 
  self.ticklecount = 0; 
  self.curticklestart = cgpointzero; 
  self.lastdirection = directionunknown; 
  if (self.state == uigesturerecognizerstatepossible) { 
    [self setstate:uigesturerecognizerstatefailed]; 
  } 
} 
 
- (void)touchesended:(nsset *)touches withevent:(uievent *)event 
{ 
  [self reset]; 
} 
 
- (void)touchescancelled:(nsset *)touches withevent:(uievent *)event 
{ 
  [self reset]; 
} 
 
@end 

调用自定义手势和上面一样,回到这样写:

- (void)handlehappy:(happygesturerecognizer *)recognizer{ 
  [self.heheplayer play]; 
} 

手势成功后播放呵呵笑的声音。

在真机上运行,按住某个view,快速左右拖动,就会发出笑的声音了。

代码解析:

先获取起始坐标:curticklestart

通过和ticklepoint的x值对比,得出当前的放下是向左还是向右。再算出移动的x的值是否比move_amt_per_tickle距离大,如果太则返回。

再判断是否有三次是不同方向的动作,如果是则手势结束,回调。

源代码:。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

  • ios uicollectionview实现横向滚动

    现在使用卡片效果的app很多,之前公司让实现一种卡片效果,就写了一篇关于实现卡片的文章。文章最后附有demo实现上我选择了使用uicollectionview ... [阅读全文]
  • iOS UICollectionView实现横向滑动

    本文实例为大家分享了ios uicollectionview实现横向滑动的具体代码,供大家参考,具体内容如下uicollectionview的横向滚动,目前我使... [阅读全文]
  • iOS13适配深色模式(Dark Mode)的实现

    iOS13适配深色模式(Dark Mode)的实现

    好像大概也许是一年前, mac os系统发布了深色模式外观, 看着挺刺激, 时至今日用着也还挺爽的终于, 随着iphone11等新手机的发售, ios 13系统... [阅读全文]
  • ios 使用xcode11 新建项目工程的步骤详解

    ios 使用xcode11 新建项目工程的步骤详解

    xcode11新建项目工程,新增了scenedelegate这个类,转而将原appdelegate负责的对ui生命周期的处理担子接了过来。故此可以理解为:ios... [阅读全文]
  • iOS实现转盘效果

    本文实例为大家分享了ios实现转盘效果的具体代码,供大家参考,具体内容如下demo下载地址: ios转盘效果功能:实现了常用的ios转盘效果,轮盘抽奖效果的实现... [阅读全文]
  • iOS开发实现转盘功能

    本文实例为大家分享了ios实现转盘功能的具体代码,供大家参考,具体内容如下今天给同学们讲解一下一个转盘选号的功能,直接上代码直接看viewcontroller#... [阅读全文]
  • iOS实现轮盘动态效果

    本文实例为大家分享了ios实现轮盘动态效果的具体代码,供大家参考,具体内容如下一个常用的绘图,主要用来打分之类的动画,效果如下。主要是ios的绘图和动画,本来想... [阅读全文]
  • iOS实现九宫格连线手势解锁

    本文实例为大家分享了ios实现九宫格连线手势解锁的具体代码,供大家参考,具体内容如下demo下载地址:效果图:核心代码://// clockview.m// 手... [阅读全文]
  • iOS实现卡片堆叠效果

    本文实例为大家分享了ios实现卡片堆叠效果的具体代码,供大家参考,具体内容如下如图,这就是最终效果。去年安卓5.0发布的时候,当我看到安卓全新的material... [阅读全文]
  • iOS利用余弦函数实现卡片浏览工具

    iOS利用余弦函数实现卡片浏览工具

    本文实例为大家分享了ios利用余弦函数实现卡片浏览工具的具体代码,供大家参考,具体内容如下一、实现效果通过拖拽屏幕实现卡片移动,左右两侧的卡片随着拖动变小,中间... [阅读全文]
验证码:
移动技术网