UIGestureRecognizer学习笔记

在 iPhone 或 iPad 的开发中,除了用 touchesBegan / touchesMoved / touchesEnded 这组方法来控制使用者的手指触控外,也可以用 UIGestureRecognizer 的衍生类別来进行判断。用 UIGestureRecognizer 的好处在于有现成的手势,开发者不用自己计算手指移动轨迹。UIGestureRecognizer的衍生类別有以下几种:
UITapGestureRecognizer
UIPinchGestureRecognizer
UIRotationGestureRecognizer
UISwipeGestureRecognizer
UIPanGestureRecognizer
UILongPressGestureRecognizer

从命名上不难了解這些类別所对应代表的手势,分別是 Tap(点一下)、Pinch(二指往內或往外拨动)、Rotation(旋转)、Swipe(滑动,快速移动)、Pan (拖移,慢速移动)以及 LongPress(长按)。這些手势別在使用上也很简单,只要在使用前定义并添加到对应的视图上即可。
The concrete subclasses of UIGestureRecognizer
are the following:
UITapGestureRecognizer

UIPinchGestureRecognizer

UIRotationGestureRecognizer

UISwipeGestureRecognizer

UIPanGestureRecognizer

UILongPressGestureRecognizer

一个gesture recognizer是针对一个特定的view的(包含其subview),用UIView的方法addGestureRecognize:去关联一个view

一个gesture recognizer是不参与UIView的事件响应链的

各个手势使用时的代码:
UITapGestureRecognizer

  • (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view from its nib.



UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];

if (![tapGesture respondsToSelector:@selector(locationInView:)]) {

    [tapGesture release];

    tapGesture = nil;

}else {

    tapGesture.delegate = self;

    tapGesture.numberOfTapsRequired = 1; // The default value is 1.

    tapGesture.numberOfTouchesRequired = 1; // The default value is 1.

    [self.view addGestureRecognizer:tapGesture];

}

}

  • (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer

{

UIView *view = [gestureRecognizer view]; // 这个view是手势所属的view,也就是增加手势的那个view



switch (gestureRecognizer.state) {

    case UIGestureRecognizerStateEnded:{ // UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded // 正常情况下只响应这个消息

        NSLog(@"======UIGestureRecognizerStateEnded || UIGestureRecognizerStateRecognized");

        break;

    }

    case UIGestureRecognizerStateFailed:{ // 

        NSLog(@"======UIGestureRecognizerStateFailed");

        break;

    }

    case UIGestureRecognizerStatePossible:{ // 

        NSLog(@"======UIGestureRecognizerStatePossible");

        break;

    }

    default:{

        NSLog(@"======Unknow gestureRecognizer");

        break;

    }

}  

}

// 询问一个手势接收者是否应该开始解释执行一个触摸接收事件

  • (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{

// CGPoint currentPoint = [gestureRecognizer locationInView:self.view];

// if (CGRectContainsPoint(CGRectMake(0, 0, 100, 100), currentPoint) ) {

// return YES;

// }

//

// return NO;

return YES;

}

// 询问delegate,两个手势是否同时接收消息,返回YES同事接收。返回NO,不同是接收(如果另外一个手势返回YES,则并不能保证不同时接收消息)the default implementation returns NO。

// 这个函数一般在一个手势接收者要阻止另外一个手势接收自己的消息的时候调用

  • (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{

    return NO;

}

// 询问delegate是否允许手势接收者接收一个touch对象

// 返回YES,则允许对这个touch对象审核,NO,则不允许。

// 这个方法在touchesBegan:withEvent:之前调用,为一个新的touch对象进行调用

  • (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{

    return YES;

}

UIPinchGestureRecognizer

  • (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view from its nib.



UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];

if (![pinchGesture respondsToSelector:@selector(locationInView:)]) {

    [pinchGesture release];

    pinchGesture = nil;

}else {

    pinchGesture.delegate = self;

    [self.view addGestureRecognizer: pinchGesture];

}  

}

  • (void)handleGesture:(UIPinchGestureRecognizer *)gestureRecognizer

{

UIView *view = [gestureRecognizer view]; // 这个view是手势所属的view,也就是增加手势的那个view







CGFloat scale = gestureRecognizer.scale;

NSLog(@"======scale: %f", scale);



CGFloat velocity = gestureRecognizer.velocity;

NSLog(@"======scvelocityale: %f", velocity);





switch (gestureRecognizer.state) {

    case UIGestureRecognizerStateEnded:{ // UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded

        NSLog(@"======UIGestureRecognizerStateEnded || UIGestureRecognizerStateRecognized");

        break;

    }

    case UIGestureRecognizerStateBegan:{ // 

        NSLog(@"======UIGestureRecognizerStateBegan");

        break;

    }

    case UIGestureRecognizerStateChanged:{ // 

        NSLog(@"======UIGestureRecognizerStateChanged");

        

        gestureRecognizer.view.transform = CGAffineTransformScale(gestureRecognizer.view.transform, gestureRecognizer.scale, gestureRecognizer.scale);

        gestureRecognizer.scale = 1; // 重置,很重要!!!

        

        break;

    }

    case UIGestureRecognizerStateCancelled:{ // 

        NSLog(@"======UIGestureRecognizerStateCancelled");

        break;

    }

    case UIGestureRecognizerStateFailed:{ // 

        NSLog(@"======UIGestureRecognizerStateFailed");

        break;

    }

    case UIGestureRecognizerStatePossible:{ // 

        NSLog(@"======UIGestureRecognizerStatePossible");

        break;

    }

    default:{

        NSLog(@"======Unknow gestureRecognizer");

        break;

    }

}  

}

recognizer.scale是pinch手势的scale值,它每次都是从1开始,以两指的距离为参考,如果捏合两指,则scale变小;如果两指向外拉,则scale变大

UIRotationGestureRecognizer

  • (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view from its nib.

UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];

if (![rotationGesture respondsToSelector:@selector(locationInView:)]) {

    [rotationGesture release];

    rotationGesture = nil;

}else {

    rotationGesture.delegate = self;

    

    [self.view addGestureRecognizer:rotationGesture];

}

}

  • (void)handleGesture:(UIRotationGestureRecognizer *)gestureRecognizer

{

UIView *view = [gestureRecognizer view]; // 这个view是手势所属的view,也就是增加手势的那个view







CGFloat rotation = gestureRecognizer.rotation;

NSLog(@"===rotation: %f", rotation);



CGFloat velocity = gestureRecognizer.velocity;

NSLog(@"======velocity: %f", velocity);









switch (gestureRecognizer.state) {

    case UIGestureRecognizerStateEnded:{ // UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded

        NSLog(@"======UIGestureRecognizerStateEnded || UIGestureRecognizerStateRecognized");

        break;

    }

    case UIGestureRecognizerStateBegan:{ // 

        NSLog(@"======UIGestureRecognizerStateBegan");

        break;

    }

    case UIGestureRecognizerStateChanged:{ // 

        NSLog(@"======UIGestureRecognizerStateChanged");

        

        gestureRecognizer.view.transform = CGAffineTransformRotate(gestureRecognizer.view.transform, gestureRecognizer.rotation);

        gestureRecognizer.rotation = 0; // 重置 这个相当重要!!! 

        

        break;

    }

    case UIGestureRecognizerStateCancelled:{ // 

        NSLog(@"======UIGestureRecognizerStateCancelled");

        break;

    }

    case UIGestureRecognizerStateFailed:{ // 

        NSLog(@"======UIGestureRecognizerStateFailed");

        break;

    }

    case UIGestureRecognizerStatePossible:{ // 

        NSLog(@"======UIGestureRecognizerStatePossible");

        break;

    }

    default:{

        NSLog(@"======Unknow gestureRecognizer");

        break;

    }

}  

}

UISwipeGestureRecognizer

  • (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view from its nib.







// right

UISwipeGestureRecognizer *swipeGestureRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];

if (![swipeGestureRight respondsToSelector:@selector(locationInView:)]) {

    [swipeGestureRight release];

    swipeGestureRight = nil;

}else {

    swipeGestureRight.delegate = self;

    swipeGestureRight.numberOfTouchesRequired = 1;// 手指个数 The default value is 1.

    swipeGestureRight.direction = UISwipeGestureRecognizerDirectionRight;// 同一个手势只能指定一个方向,不能同时指定多个方向,要指定多个方向 必须用多个手势

    [self.view addGestureRecognizer:swipeGestureRight];

}



// left

UISwipeGestureRecognizer *swipeGestureLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];

if (![swipeGestureLeft respondsToSelector:@selector(locationInView:)]) {

    [swipeGestureLeft release];

    swipeGestureLeft = nil;

}else {

    swipeGestureLeft.delegate = self;

    swipeGestureLeft.numberOfTouchesRequired = 1;// 手指个数 The default value is 1.

    swipeGestureLeft.direction = UISwipeGestureRecognizerDirectionLeft;// 同一个手势只能指定一个方向,不能同时指定多个方向,要指定多个方向 必须用多个手势

    [self.view addGestureRecognizer:swipeGestureLeft];

}



// Up

UISwipeGestureRecognizer *swipeGestureUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];

if (![swipeGestureUp respondsToSelector:@selector(locationInView:)]) {

    [swipeGestureUp release];

    swipeGestureUp = nil;

}else {

    swipeGestureUp.delegate = self;

    swipeGestureUp.numberOfTouchesRequired = 1;// 手指个数 The default value is 1.

    swipeGestureUp.direction = UISwipeGestureRecognizerDirectionUp;// 同一个手势只能指定一个方向,不能同时指定多个方向,要指定多个方向 必须用多个手势

    [self.view addGestureRecognizer:swipeGestureUp];

}



// Down

UISwipeGestureRecognizer *swipeGestureDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];

if (![swipeGestureDown respondsToSelector:@selector(locationInView:)]) {

    [swipeGestureDown release];

    swipeGestureDown = nil;

}else {

    swipeGestureDown.delegate = self;

    swipeGestureDown.numberOfTouchesRequired = 1;// 手指个数 The default value is 1.

    swipeGestureDown.direction = UISwipeGestureRecognizerDirectionDown;// 同一个手势只能指定一个方向,不能同时指定多个方向,要指定多个方向 必须用多个手势

    [self.view addGestureRecognizer:swipeGestureDown];

}

}

  • (void)handleGesture:(UISwipeGestureRecognizer *)gestureRecognizer

{

UIView *view = [gestureRecognizer view]; // 这个view是手势所属的view,也就是增加手势的那个view





UISwipeGestureRecognizerDirection direction = gestureRecognizer.direction;

switch (direction) {

    case UISwipeGestureRecognizerDirectionRight:

    {

        NSLog(@"direction==UISwipeGestureRecognizerDirectionRight");

        break;

    }

    case UISwipeGestureRecognizerDirectionLeft:

    {

        NSLog(@"direction==UISwipeGestureRecognizerDirectionLeft");

        break;

    }

    case UISwipeGestureRecognizerDirectionUp:

    {

        NSLog(@"direction==UISwipeGestureRecognizerDirectionUp");

        break;

    }

    case UISwipeGestureRecognizerDirectionDown:

    {

        NSLog(@"direction==UISwipeGestureRecognizerDirectionDown");

        break;

    }

    default:

        break;

}







switch (gestureRecognizer.state) {

    case UIGestureRecognizerStateEnded:{ // UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded

        NSLog(@"======UIGestureRecognizerStateEnded || UIGestureRecognizerStateRecognized");

        break;

    }

    default:{

        NSLog(@"======Unknow gestureRecognizer");

        break;

    }

}  

}

UIPanGestureRecognizer

  • (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view from its nib.



UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];

view.backgroundColor = [UIColor blueColor];

[self.view addSubview:view];





UIPanGestureRecognizer *panPressGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];

if (![panPressGesture respondsToSelector:@selector(locationInView:)]) {

    [panPressGesture release];

    panPressGesture = nil;

}else {

    panPressGesture.delegate = self;

    panPressGesture.maximumNumberOfTouches = NSUIntegerMax;// The default value is NSUIntegerMax. 

   

    panPressGesture.minimumNumberOfTouches = 1;// The default value is 1.

    [view addGestureRecognizer:panPressGesture];

}

}

// 拖拽手势

  • (void)handleGesture:(UIPanGestureRecognizer *)gestureRecognizer

{

UIView *view = [gestureRecognizer view]; // 这个view是手势所属的view,也就是增加手势的那个view





switch (gestureRecognizer.state) {

    case UIGestureRecognizerStateBegan:{ 

        NSLog(@"======UIGestureRecognizerStateBegan");

        break;

    }

    case UIGestureRecognizerStateChanged:{ 

        NSLog(@"======UIGestureRecognizerStateChanged");

        

       

        

        CGPoint translation = [gestureRecognizer translationInView:self.view];

        view.center = CGPointMake(gestureRecognizer.view.center.x + translation.x, gestureRecognizer.view.center.y + translation.y);

        [gestureRecognizer setTranslation:CGPointMake(0, 0) inView:self.view];//  注意一旦你完成上述的移动,将translation重置为0十分重要。否则translation每次都会叠加,很快你的view就会移除屏幕!

        break;

    }

    case UIGestureRecognizerStateCancelled:{ 

        NSLog(@"======UIGestureRecognizerStateCancelled");

        break;

    }

    case UIGestureRecognizerStateFailed:{ 

        NSLog(@"======UIGestureRecognizerStateFailed");

        break;

    }

    case UIGestureRecognizerStatePossible:{ 

        NSLog(@"======UIGestureRecognizerStatePossible");

        break;

    }

    case UIGestureRecognizerStateEnded:{ // UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded

        

       

        

        NSLog(@"======UIGestureRecognizerStateEnded || UIGestureRecognizerStateRecognized");

        

        CGPoint velocity = [gestureRecognizer velocityInView:self.view];// 分别得出x,y轴方向的速度向量长度(velocity代表按照当前速度,每秒可移动的像素个数,分xy轴两个方向)

        CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));// 根据直角三角形的算法算出综合速度向量长度

        

        // 如果长度小于200,则减少基本速度,否则增加它。

        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(view.center.x + (velocity.x * slideFactor),

                                         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:^{

            view.center = finalPoint;  

        } completion:nil];

        

        break;

    }

    default:{

        NSLog(@"======Unknow gestureRecognizer");

        break;

    }

}  

}

UILongPressGestureRecognizer

  • (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view from its nib.

UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];

if (![longPressGesture respondsToSelector:@selector(locationInView:)]) {

    [longPressGesture release];

    longPressGesture = nil;

}else {

    longPressGesture.delegate = self;

    longPressGesture.numberOfTapsRequired = 0;      // The default number of taps is 0.

    longPressGesture.minimumPressDuration = 0.1f;    // The default duration is is 0.5 seconds.

    longPressGesture.numberOfTouchesRequired = 1;   // The default number of fingers is 1.

    longPressGesture.allowableMovement = 10;        // The default distance is 10 pixels.

    [self.view addGestureRecognizer:longPressGesture];

}

}

  • (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer

{

UIView *view = [gestureRecognizer view]; // 这个view是手势所属的view,也就是增加手势的那个view



switch (gestureRecognizer.state) {

    case UIGestureRecognizerStateEnded:{ // UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded

        NSLog(@"======UIGestureRecognizerStateEnded || UIGestureRecognizerStateRecognized");

        break;

    }

    case UIGestureRecognizerStateBegan:{ // 

        NSLog(@"======UIGestureRecognizerStateBegan");

        break;

    }

    case UIGestureRecognizerStateChanged:{ // 

        NSLog(@"======UIGestureRecognizerStateChanged");

        break;

    }

    case UIGestureRecognizerStateCancelled:{ // 

        NSLog(@"======UIGestureRecognizerStateCancelled");

        break;

    }

    case UIGestureRecognizerStateFailed:{ // 

        NSLog(@"======UIGestureRecognizerStateFailed");

        break;

    }

    case UIGestureRecognizerStatePossible:{ // 

        NSLog(@"======UIGestureRecognizerStatePossible");

        break;

    }

    default:{

        NSLog(@"======Unknow gestureRecognizer");

        break;

    }

}  

}

// 询问一个手势接收者是否应该开始解释执行一个触摸接收事件

  • (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{

    CGPoint currentPoint = [gestureRecognizer locationInView:self.view];

    if (CGRectContainsPoint(CGRectMake(0, 0, 100, 100), currentPoint) ) {

      return YES;
    

    }

return NO;

}

// 询问delegate,两个手势是否同时接收消息,返回YES同事接收。返回NO,不同是接收(如果另外一个手势返回YES,则并不能保证不同时接收消息)the default implementation returns NO。

// 这个函数一般在一个手势接收者要阻止另外一个手势接收自己的消息的时候调用

  • (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{

    return NO;

}

// 询问delegate是否允许手势接收者接收一个touch对象

// 返回YES,则允许对这个touch对象审核,NO,则不允许。

// 这个方法在touchesBegan:withEvent:之前调用,为一个新的touch对象进行调用

  • (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{

    return YES;

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容