zoukankan      html  css  js  c++  java
  • iOS手势识别

    一、手势识别与触摸事件

    1、如果想监听一个view上面的触摸事件,可选的做法是:

    (1)自定义一个view

    (2)实现view的touches方法,在方法内部实现具体处理代码

    2、通过touches方法监听view触摸事件,有很明显的几个缺点

    (1)必须得自定义view

    (2)由于是在view内部的touches方法中监听触摸事件,因此默认情况下,无法让其他外界对象监听view的触摸事件

    (3)不容易区分用户的具体手势行为

    3、iOS 3.2之后,苹果推出了手势识别功能(Gesture Recognizer),在触摸事件处理方面,大大简化了开发者的开发难度

    二、手势识别——Gesture Recognizer

    1、手势识别器:UIGestureRecognizer

    (1)UIGestureRecognizer是一个抽象类,定义了所有手势的基本行为,使用它的子类才能处理具体的手势

    (2)子类的继承和功能

    图示:

     

    2、手势识别的使用方法及步骤

    (1)创建手势识别实例

    (2)设置手势识别属性,例如手指数量,方向等

    (3)将手势识别附加到指定的视图之上

    (4)编写手势触发监听方法

    (5)手势触发监听方法后,要还原手势识别实例的属性,比如:获取了缩放比例,然后给某个控件进行了缩放,最后再把缩放比例还原为1。这样后续的手势操作会从新开始,避免错误

    3、手势识别的状态

    (1)类似于触摸事件,手势识别实例包含了属性 state,可以区别此时手势的状态

    (2)state属性为枚举类型:

       <1> 没有触摸事件发生,所有手势识别的默认状态

        UIGestureRecognizerStatePossible,

        <2> 一个手势已经开始但尚未改变或者完成时

        UIGestureRecognizerStateBegan, (类似于 touchesBegan)

        <3> 手势状态改变

        UIGestureRecognizerStateChanged, (类似于 touchesMoved)

        <4> 手势完成

        UIGestureRecognizerStateEnded, (类似于 touchesEnded)

        <5> 手势取消,恢复至Possible状态

        UIGestureRecognizerStateCancelled, (比如手指按下按钮,然后从其他地方抬起)

        <6> 手势失败,恢复至Possible状态

        UIGestureRecognizerStateFailed,

        <7> 识别到手势结束

        UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded

    4、不同手势识别子类具有不同的属性或方法,几个重要的举例如下:

    (1)在“轻点”手势中: 

      <1> 需要连续敲击2次触发手势

      tap.numberOfTapsRequired = 2;

      <2> 需要2根手指一起敲击

      tap.numberOfTouchesRequired = 2;

    (2)在“旋转”手势中:

      <1>获取用户旋转角度 

      CGFloat rotation;

       

      <2>获取用户旋转速度

       CGFloat velocity

    (3)在“轻扫”手势中:

       <1>扫动的方向,注意,一个轻扫手势识别对象,只能对应一个扫动方向

       UISwipeGestureRecognizerDirection

    (4)在“拖拽”手势中:

       <1> 获取移动的距离 ,这个是对象方法

       - (CGPoint)translationInView:(nullable UIView *)view; 

      <2>清除手势移动的距离(为了下次手势事件的正确计算)

        例: [pan setTranslation:CGPointZero inView:self.view];

    5、实现多手势识别(比如缩放的同时可以旋转)

    (1)设置手势识别器的代理

      

    (2)实现相应的代理方法,支持多手势识别。

    三、demo实例

    1、图示

     

    2、贴出部分代码

    #pragma mark - 长按手势
    - (IBAction)longPressBtnClick:(id)sender {
        
        //长按手势识别器,正常下会执行两次方法,不晓得为啥     
        UILongPressGestureRecognizer * longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longClick:)];
        
        [self.view addGestureRecognizer:longPress];
        //代理
        longPress.delegate = self;
        
    }
    
    -(void)longClick:(UILongPressGestureRecognizer *)longPress
    {
    
        //根据状态判断
        if(longPress.state==UIGestureRecognizerStateBegan)
        {
            NSLog(@"开始长按了~~");
    
        }
        
    }
    
    #pragma mark - 旋转手势
    - (IBAction)rotateBtnClick {
     
        UIRotationGestureRecognizer * rotate = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotateClick:)];
        
        [self.view addGestureRecognizer:rotate];
        
        //增加代理
         rotate.delegate =self;
          
    }
    
    -(void)rotateClick:(UIRotationGestureRecognizer *)rotate
    {
    
        CGFloat ratation = rotate.rotation;
        self.headerView.transform = CGAffineTransformRotate(self.headerView.transform, ratation);
    
        //清除掉累加的 rotation
        rotate.rotation=0;
    }
    
    
    
    
    #pragma mark - 缩放手势
    - (IBAction)pinchBtnClick {
        
        UIPinchGestureRecognizer * pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinchClick:)];
        
        [self.view addGestureRecognizer:pinch];
        
        //增加代理
        pinch.delegate = self;
        
    }
    
    
    -(void)pinchClick:(UIPinchGestureRecognizer *)pinch
    {
        CGFloat scale = pinch.scale;
        self.headerView.transform = CGAffineTransformScale(self.headerView.transform, scale, scale);
        
        //同样清除
        pinch.scale = 1;
    
    }
    
    
    
    
    #pragma mark - 轻扫手势
    - (IBAction)swipeBtnClick {
    
        UISwipeGestureRecognizer * swipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeClick:)];
        
        //向右扫动手势
        swipe.direction= UISwipeGestureRecognizerDirectionRight;
        [self.view addGestureRecognizer:swipe];
        
        UISwipeGestureRecognizer * swipe2 =[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeClick:)];
        
        //向左扫动手势
        swipe2.direction= UISwipeGestureRecognizerDirectionLeft;
        [self.view addGestureRecognizer:swipe2];
    }
    
    -(void)swipeClick:(UISwipeGestureRecognizer *)swipe
    {
    
        if (swipe.direction==UISwipeGestureRecognizerDirectionRight) {    
            [UIView animateWithDuration:0.3 animations:^{
           
            self.headerView.transform = CGAffineTransformTranslate(self.headerView.transform, 100, 0);
                
                
            }completion:^(BOOL finished) {
                
                [UIView animateWithDuration:0.5 animations:^{
                    self.headerView.transform = CGAffineTransformIdentity;
                    
                }];
                
                
            }];
         
        }
        else if (swipe.direction==UISwipeGestureRecognizerDirectionLeft) {
        
            [UIView animateWithDuration:0.3 animations:^{
                
                    self.headerView.transform = CGAffineTransformTranslate(self.headerView.transform, -100, 0);          
                
            }completion:^(BOOL finished) {
                
                [UIView animateWithDuration:0.5 animations:^{
                    self.headerView.transform = CGAffineTransformIdentity;
    
                }];
            }];
        }
    }
    
    
    
    
    #pragma mark - 拖拽手势
    - (IBAction)panBtnClick {
      
        UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panClick:)];
        
        [self.view addGestureRecognizer:pan];
         
    }
    
    
    -(void)panClick:(UIPanGestureRecognizer *)pan
    {
        CGPoint point = [pan translationInView:self.view];
        
        self.headerView.transform = CGAffineTransformTranslate(self.headerView.transform, point.x, point.y);
    
        [pan setTranslation:CGPointZero inView:self.view];
    }
    
    
    //手势识别代理实现
    -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    {
        return YES;
    
    }

    四、补充

    1、同一个控件添加多个手势,触发冲突的问题,比如双击和单击。

    (1)问题描述

      手势是可以互相关联的,例如 Tap 与 LongPress、Swipe与 Pan,或是 Tap 一次与Tap 两次。当一个 UIView 同时添加两个相关联的手势时,到底我这一下手指头按的要算是 Tap 还是 LongPress?如果照预设作法来看,只要「先满足条件」的就会跳出并呼叫对应方法,举例来说,如果同时注册了 Pan 和 Swipe,只要手指头一移动就会触发 Pan 然后跳出,因而永远都不会发生 Swipe;单点与双点的情形也是一样,永远都只会触发单点,不会有双点。

    (2)解决方法:requireGestureRecognizerToFail --手势的对象方法

      指定某一个 recognizer,即便自己已经满足条件了,也不会立刻触发,会等到该指定的 recognizer 确定失败之后才触发。

    (3)举例  

      //如果双击确定侦测失败才会触发单击

      [singleRecognizer requireGestureRecognizerToFail:doubleRecognizer];

  • 相关阅读:
    docker基础:docker网络模式
    WEB架构师成长之路之一-走正确的路(转载)
    DDD(领域驱动设计)
    C#泛型和泛型约束(转载)
    MES系统介绍
    vue中 computed和watch的一些简单理解(区别)(转载)
    sqlserver常用表值函数
    SQLServerAgent 当前未运行,因此无法将此操作通知它。
    浅谈敏捷开发(转载)
    认证、授权、鉴权和权限控制(转载)
  • 原文地址:https://www.cnblogs.com/cleven/p/5374644.html
Copyright © 2011-2022 走看看