参考文章http://blog.jobbole.com/65846/


1. UIGestureRecognizer介绍

UIGestureRecognizer类是个抽象类,下面的子类是具体的手势,开发这可以直接使用这些手势识别。

UITapGestureRecognizer// 点击

UIPinchGestureRecognizer//二指往內或往外拨动,平时经常用到的缩放

UIRotationGestureRecognizer //旋转

UISwipeGestureRecognizer //滑动,快速移动

UIPanGestureRecognizer //拖移,慢速移动

UILongPressGestureRecognizer //长按


2、使用手势的步骤

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

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

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

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


3、Pan 拖动手势:

//新建一个ImageView,然后添加手势UIImageView*snakeImageView=[[UIImageViewalloc]initWithImage:[UIImagep_w_picpathNamed:@"snake.png"]];snakeImageView.frame=CGRectMake(50,50,100,160);UIPanGestureRecognizer*panGestureRecognizer=[[UIPanGestureRecognizeralloc]initWithTarget:selfaction:@selector(handlePan:)];[snakeImageViewaddGestureRecognizer:panGestureRecognizer];[self.viewsetBackgroundColor:[UIColorwhiteColor]];[self.viewaddSubview:snakeImageView];//回调方法:-(void)handlePan:(UIPanGestureRecognizer*)recognizer{CGPointtranslation=[recognizertranslationInView:self.view];recognizer.view.center=CGPointMake(recognizer.view.center.x+translation.x,recognizer.view.center.y+translation.y);[recognizersetTranslation:CGPointZeroinView:self.view];}


4、Pinch缩放手势

UIPinchGestureRecognizer*pinchGestureRecognizer=[[UIPinchGestureRecognizeralloc]initWithTarget:selfaction:@selector(handlePinch:)];-(void)handlePinch:(UIPinchGestureRecognizer*)recognizer{recognizer.view.transform=CGAffineTransformScale(recognizer.view.transform,recognizer.scale,recognizer.scale);recognizer.scale=1;}


5、Rotation旋转手势

UIRotationGestureRecognizer*rotateRecognizer=[[UIRotationGestureRecognizeralloc]initWithTarget:selfaction:@selector(handleRotate:)];[snakeImageViewaddGestureRecognizer:rotateRecognizer];-(void)handleRotate:(UIRotationGestureRecognizer*)recognizer{recognizer.view.transform=CGAffineTransformRotate(recognizer.view.transform,recognizer.rotation);recognizer.rotation=0;}


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

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

-(void)viewDidLoad{[superviewDidLoad];UIImageView*snakeImageView=[[UIImageViewalloc]initWithImage:[UIImagep_w_picpathNamed:@"snake.png"]];UIImageView*dragonImageView=[[UIImageViewalloc]initWithImage:[UIImagep_w_picpathNamed:@"dragon.png"]];snakeImageView.frame=CGRectMake(120,120,100,160);dragonImageView.frame=CGRectMake(50,50,100,160);[self.viewaddSubview:snakeImageView];[self.viewaddSubview:dragonImageView];for(UIView*viewinself.view.subviews){UIPanGestureRecognizer*panGestureRecognizer=[[UIPanGestureRecognizeralloc]initWithTarget:selfaction:@selector(handlePan:)];UIPinchGestureRecognizer*pinchGestureRecognizer=[[UIPinchGestureRecognizeralloc]initWithTarget:selfaction:@selector(handlePinch:)];UIRotationGestureRecognizer*rotateRecognizer=[[UIRotationGestureRecognizeralloc]initWithTarget:selfaction:@selector(handleRotate:)];[viewaddGestureRecognizer:panGestureRecognizer];[viewaddGestureRecognizer:pinchGestureRecognizer];[viewaddGestureRecognizer:rotateRecognizer];[viewsetUserInteractionEnabled:YES];}[self.viewsetBackgroundColor:[UIColorwhiteColor]];}


7、拖动(pan手势)速度(以较快的速度拖放后view有滑行的效果)

如何实现呢?

1.监视手势是否结束

2.监视触摸的速度

-(void)handlePan:(UIPanGestureRecognizer*)recognizer{CGPointtranslation=[recognizertranslationInView:self.view];recognizer.view.center=CGPointMake(recognizer.view.center.x+translation.x,recognizer.view.center.y+translation.y);[recognizersetTranslation:CGPointZeroinView:self.view];if(recognizer.state==UIGestureRecognizerStateEnded){CGPointvelocity=[recognizervelocityInView:self.view];CGFloatmagnitude=sqrtf((velocity.x*velocity.x)+(velocity.y*velocity.y));CGFloatslideMult=magnitude/200;NSLog(@"magnitude:%f,slideMult:%f",magnitude,slideMult);floatslideFactor=0.1*slideMult;//IncreaseformoreofaslideCGPointfinalPoint=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);[UIViewanimateWithDuration:slideFactor*2delay:0options:UIViewAnimationOptionCurveEaseOutanimations:^{recognizer.view.center=finalPoint;}completion:nil];}

代码实现解析:

1.计算速度向量的长度(估计大部分都忘了)这些知识了。

2.如果速度向量小于200,那就会得到一个小于的小数,那么滑行会很短

3.基于速度和速度因素计算一个终点

4.确保终点不会跑出父View的边界

5.使用UIView动画使view滑动到终点

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


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

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

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

-(BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizershouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer{returnYES;}

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

panGestureRecognizer.delegate=self;pinchGestureRecognizer.delegate=self;rotateRecognizer.delegate=self;

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

9、tap点击手势

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

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

-(AVAudioPlayer*)loadWav:(NSString*)filename{NSURL*url=[[NSBundlemainBundle]URLForResource:filenamewithExtension:@"wav"];NSError*error;AVAudioPlayer*player=[[AVAudioPlayeralloc]initWithContentsOfURL:urlerror:&error];if(!player){NSLog(@"Errorloading%@:%@",url,error.localizedDescription);}else{[playerprepareToPlay];}returnplayer;}

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

#import<UIKit/UIKit.h>#import<AVFoundation/AVFoundation.h>@interfaceViewController:UIViewController<UIGestureRecognizerDelegate>@property(strong)AVAudioPlayer*chompPlayer;@property(strong)AVAudioPlayer*hehePlayer;@end-(void)handleTap:(UITapGestureRecognizer*)recognizer{[self.chompPlayerplay];}

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

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


10、手势的依赖性

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

[tapRecognizerrequireGestureRecognizerToFail:panGestureRecognizer];

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


11、自定义手势

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

–touchesBegan:withEvent:–touchesMoved:withEvent:–touchesEnded:withEvent:-touchesCancelled:withEvent:

新建一个类,继承UIGestureRecognizer,代码如下:

.h文件

#import<UIKit/UIKit.h>typedefenum{DirectionUnknown=0,DirectionLeft,DirectionRight}Direction;@interfaceHappyGestureRecognizer:UIGestureRecognizer@property(assign)inttickleCount;@property(assign)CGPointcurTickleStart;@property(assign)DirectionlastDirection;@end

.m文件

#import"HappyGestureRecognizer.h"#import<UIKit/UIGestureRecognizerSubclass.h>#defineREQUIRED_TICKLES2#defineMOVE_AMT_PER_TICKLE25@implementationHappyGestureRecognizer-(void)touchesBegan:(NSSet*)toucheswithEvent:(UIEvent*)event{UITouch*touch=[touchesanyObject];self.curTickleStart=[touchlocationInView:self.view];}-(void)touchesMoved:(NSSet*)toucheswithEvent:(UIEvent*)event{//Makesurewe'vemovedaminimumamountsincecurTickleStartUITouch*touch=[touchesanyObject];CGPointticklePoint=[touchlocationInView:self.view];CGFloatmoveAmt=ticklePoint.x-self.curTickleStart.x;DirectioncurDirection;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){[selfsetState:UIGestureRecognizerStateEnded];}}}-(void)reset{self.tickleCount=0;self.curTickleStart=CGPointZero;self.lastDirection=DirectionUnknown;if(self.state==UIGestureRecognizerStatePossible){[selfsetState:UIGestureRecognizerStateFailed];}}-(void)touchesEnded:(NSSet*)toucheswithEvent:(UIEvent*)event{[selfreset];}-(void)touchesCancelled:(NSSet*)toucheswithEvent:(UIEvent*)event{[selfreset];}@end

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

-(void)handleHappy:(HappyGestureRecognizer*)recognizer{[self.hehePlayerplay];}

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

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

代码解析:

先获取起始坐标:curTickleStart

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

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