iOS - 使用手势处理器(UIGestureRecognize

2020-12-02  本文已影响0人  __season____

使用手势处理器(UIGestureRecognizer)

通过手势处理器处理用户触碰事件更加简单,而且无论处理哪种触碰手势,都可面向 UIGestureRecognizer 编程,UIGestureRecognizer 提供了如下子类。

使用手势处理器处理用户触碰手势的编程步骤如下:
UIGestureRecognizer 作为所有手势处理器的基类,它提供如下常用的方法和属性:

-locationInView: (UIView*)view返回该手势在 view 控件中的触碰位置

-view返回激发该手势的 UI 控件

1.1、 使用 UITapGestureRecognizer 处理点击手势

UITapGestureRecognizer 还提供了如下两个属性:

@interface ViewController ()
{
    UIImage* srcImage;
    CGFloat  currentScale;//当前图片的缩放比
    CGFloat  currentRotation;//当前图片的旋转    
}
@property (nonatomic,strong)UIImageView *cView;
@end
@implementation ViewController

-(void)viewDidLoad
{
    [super viewDidLoad];

     _cView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
     _cView.backgroundColor = [UIColor redColor];
     [self.view addSubview:_cView];

    //允许用户交互,支持多点触碰
     _cView.userInteractionEnabled = YES;//允许用户交互
     _cView.multipleTouchEnabled = YES;//支持多点触碰

#pragma mark --------- UITapGestureRecognizer 点击手势 ---------    
//一共创建了 5 个手势处理器,这些手势处理器分别用于检测用户的 1 次、2 次、3次、4 次、5 次点击
   // for (int i=1; i<6; i++){
        
        //创建手势处理器,指定使用该控制器的 handletap:方法处理手势
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handletap:)];
        //设置该点击手势处理器只处理几次连击事件
        tap.numberOfTapsRequired = 1;//处理手指 点击几次 的事件
        
        //设置该点击手势处理器只处理两个手指的触碰事件

        tap.numberOfTouchesRequired = 1;
        [_cView addGestureRecognizer:tap];//为 cView控件添加手势处理器
   // }
}

#pragma mark --------- UITapGestureRecognizer 点击手势 ---------    
//当该方法被激发时,手势处理器会作为参数传给该方法的参数
-(void)handletap:(UITapGestureRecognizer*) gesture
{
    
    NSInteger touchNumber = gesture.numberOfTouchesRequired;
    NSInteger tapNumber = gesture.numberOfTapsRequired;
    NSLog(@"用户使用%d 个手指进行触碰,触碰次数为:%d", touchNumber, tapNumber);
}

 @end

1.2 、使用 UIPinchGestureRecognizer 处理捏合手势

在用户使用两个手指在屏幕上捏合的过程中,程序可通过 UIPinchGestureRecognizer检测到用户的这种捏合手势。

使用 UIPinchGestureRecognizer 处理捏合手势的步骤与使用 UITapGestureRecognizer 的步骤完全相同。 UIPinchGestureRecognizer定义了如下两个属性来获取捏合相关信息。

-(void)viewDidLoad
{
    [super viewDidLoad];
#pragma mark --------- UIPinchGestureRecognizer 捏合手势 ---------        
        //创建手势处理器,指定使用该控制器的 handletap:方法处理手势
        UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
        //设置该点击手势处理器只处理几次连击事件

        //设置该点击手势处理器只处理两个手指的触碰事件
        [_cView addGestureRecognizer:pinch];//为 cView控件添加手势处理器
}

#pragma mark --------- UIPinchGestureRecognizer 捏合手势 ---------    
-(void)handlePinch:(UIPinchGestureRecognizer*) gesture
{
        CGFloat velocity= gesture.velocity;//获取捏合的速度
        CGFloat scale = gesture.scale;//获取捏合的比例
        NSLog(@"用户捏合的速度为 %f     比例为为:%f", velocity, scale);
}

实例:通过捏合手势缩放图片

捏合手势处理器可以检测到用户手势捏合的比例,解析该捏合比例即可对图片进行缩放。本实例将通过捏合手势对图片进行缩放。

@implementation ViewController  
-(void)viewDidLoad
{
    [super viewDidLoad];

#pragma mark --------- UIPinchGestureRecognizer 捏合手势 ---------      
   //设置初始的缩放比例
    currentScale =1;
    //创建 UIPinchGestureRecognizer 手势处理器,该手势处理器激发 scaleimage:方法

     UIPinchGestureRecognizer* gesture= [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(scaleImage:)];

    //为 imageview 添加手势处理器
      [_cView addGestureRecognizer: gesture];

}

#pragma mark --------- UIPinchGestureRecognizer 捏合手势 ---------    
-(void)scaleImage:(UIPinchGestureRecognizer*)gesture
{
      CGFloat gestureScale= gesture.scale;
    //如果捏合手势刚刚开始
     if  (gesture.state ==UIGestureRecognizerStateBegan){
        //计算当前缩放比
         currentScale =_cView.image.size.width/srcImage.size.width;
     }

    //根据手势处理器的缩放比例计算图片缩放后的目标大小
     CGSize targetSize = CGSizeMake( srcImage.size.width * gestureScale  * currentScale , srcImage.size.height *gestureScale*currentScale);

     //对图片进行缩放
     _cView.image = [srcImage imageByScalingToSize: targetSize];
  
}

-(UIImage*)imageByScalingToSize:(CGSize)targetSize
{
    //开始绘图
    UIGraphicsBeginImageContext(targetSize);
    
    
    //定义图片缩放后的区域,无须保持纵横比,所以直接缩放
    CGRect anchorRect = CGRectZero;
    anchorRect.origin = CGPointZero;
    
    anchorRect.size = targetSize;
    
    [srcImage drawInRect: anchorRect]; //将图片本身绘制到 auchorrect 区域中
    
    //获取绘制后生成的新图片
    UIImage* newimage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return newimage; //返回新图片
}

1.3 、使用 UIRotationGestureRecognizer 处理 旋转手势

如果用户使用两个手指在屏幕上旋转,程序可通过 UIRotationGestureRecognizer 检测到用户的这种 旋转手势。

使用 UIRotationGestureRecognizer处理旋转手势的步骤与使用其他手势处理器的步骤完全相同。UIRotationGestureRecognizer 定义了如下两个属性来获取旋转相关信息:

实例:通过 旋转手势 旋转图片

本实例将会对前面的实例进行改进,在前面实例的基础上增加一个旋转手势处理器,从而让该应用既可根据用户捏合手势对图片进行缩放,也可根据用户旋转手势对图片进行旋转。

-(void)viewDidLoad
{
    [super viewDidLoad];
#pragma mark --------- UIRotationGestureRecognizer 旋转手势 ---------    
    currentRotation =0;
     //创建 UIRotationGestureRecognizer 旋转手势处理器,该手势处理器激发 rotationImage:方法
    UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationImage:)];
    //为 imageview 添加手势处理器
    [_cView addGestureRecognizer:rotationGesture];

}

#pragma mark --------- UIRotationGestureRecognizer 旋转手势 ---------    
//该方法将会根据手势旋转的弧度对图片进行旋转(程序同样使用了 Uiimage+SeCategory 的方法来旋转图片
-(void)rotationImage:(UIRotationGestureRecognizer*)gesture
{
      //获取手势旋转的弧度
     CGFloat rotation = rotationGesture.rotation;

    //根据当前缩放比例计算缩放后的目标图片大小
    CGSize targetSize =CGSizeMake(srcImage.size.width*currentScale,srcImage.size.height*currentScale );

    //对图片进行缩放、旋转
    
    _cView.image =[[_cView.image imageByScalingToSize:targetSize] imageRotationByRadians:currentRotation +rotation];

    //如果旋转手势结束

     if  (rotationGesture.state ==UIGestureRecognizerStateEnded)
     {
         currentRotation = currentRotation+ rotation;
     }
  
}

1.4、 使用 UISwipeGestureRecognizer 处理轻扫手势

当用户使用一个或者多个手指快速“扫”过屏幕时,程序可通过 UISwipeGestureRecognizer 检测到用户的这种轻扫手势。

使用 UISwipeGestureRecognizer/处理轻扫手势的步骤与使用其他手势处理器的步骤完全相同。UISwipeGestureRecognizer 定义了如下两个属性来设置相关信息:

下面示例将会示范使用 UISwipeGestureRecognizer 处理 轻扫 手势。在控制器类中使用 UISwipeGestureRecognizer来检测、处理用户的轻扫手势。下面是该控制器类的实现代码。

-(void)viewDidLoad
{
    [super viewDidLoad];
#pragma mark --------- UISwipeGestureRecognizer 轻扫手势 ---------    
       //创建了 4 个轻扫手势处理器,这 4 个手势处理器分别处理向上、向下、向左、向右 4 个方向的手势
    for (int i=0; i<4; i++){

        //创建 点击手势处理器,指定使用该控制器的 handletap:方法处理手势
        UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)];
        
        //设置该手势只处理器 1个手指的轻扫事件
        swipeGesture.numberOfTouchesRequired = 1;

        //设置该点击手势处理器只处理两个手指的触碰事件
        /*
         direction :设置该手势处理器处理该方向的轻扫。该属性支持 UISwipeGestureRecognizerDirectionRight (1 << 0) UISwipeGestureRecognizerDirectionLeft (1  <<1) UISwipeGestureRecognizerDirectionUp  (1 << 2)
         UISwipeGestureRecognizerDirectionDown (1 << 3)
         */
        swipeGesture.direction = 1 << i;
        [_cView addGestureRecognizer:swipeGesture];//
    }
}

#pragma mark --------- UISwipeGestureRecognizer 轻扫手势 ---------    
-(void)handleSwipe:(UISwipeGestureRecognizer*)gesture {
   
    //获取轻扫手势的方向
    NSInteger direction= gesture.direction;
    
    //根据手势方向的值得到方向字符串
    NSString* dirStr = direction == UISwipeGestureRecognizerDirectionRight? @"向右": (direction == UISwipeGestureRecognizerDirectionLeft ? @"向左":(direction == UISwipeGestureRecognizerDirectionUp ? @"向上":@"向下"));
    
    NSInteger touchNum = gesture.numberOfTouchesRequired;
    
    NSLog(@"用户使用%ld 个手指进行轻扫,方向为:%@",(long)touchNum,dirStr);
}

实例:贪食蛇 (使用 轻扫手势UISwipeGestureRecognizer )

轻扫手势处理器UISwipeGestureRecognizer在游戏中的应用十分广泛,比如在经典的贪食蛇游戏中,可以让用户通过轻扫手势处理器来改变蛇的移动方向。

贪食蛇的关键数据就是记录蛇的身体蛇身包含多个点多个点的数据用于确定蛇身的位置,由于蛇身的长度会动态改变,因此程序将会使用 NSMutableArray 来记录蛇身的每个点。

除此之外,贪食蛇只有两个需要处理的逻辑。

创建一个 Single View Application,该应用将会包含一个应用程序委托类和一个视图控制器类,但程序还需要一个自定义 Uiview 控件类,该控件类负责绘制贪食蛇的游戏界面。

下面是自定义的 FK Snake View 类(该类继承了 Uiview)的接口代码。

贪吃蛇的代码有时间补上

1.5 、使用 UIPanGestureRecognizer 处理拖动手势

在用户使用一个或多个手指在屏幕上拖动的过程中,程序可通过 UIPanGestureRecognizer检测到用户的这种拖动手势。

使用 UIPanGestureRecognizer 处理拖动手势的步骤与使用其他手势处理器的步骤完全相同。UIPanGestureRecognizer 定义了如下两个属性来设置该手势处理器的相关信息:

除此之外,该手势处理器还提供了如下方法来获取拖动相关信息 :

下面示例将会示范使用 UIPanGestureRecognizer 处理拖动手势。在控制器类中使用 UIPanGestureRecognizer 来检测用户的拖动手势。下面是该控制器类的实现代码。

注意:1、locationInView: 手指在视图上的位置(x,y)就是手指在视图本身坐标系的位置(以视图的坐标为(0,0));
2、translationInView : 手指在视图上移动的位置(x,y)向下和向右为正,向上和向左为负。

   //获取多个触碰点中任意一个触碰点
    UITouch* touch = [touches anyObject];
    //获取手指在_cView视图上的位置(x,y)
    //就是手指在_cView视图本身坐标系的位置(以_cView视图的坐标为(0,0));
    CGPoint point = [touch locationInView:_cView];
    //获取手指在视图上移动的位置(x,y)向下和向右为正,向上和向左为负。
    CGPoint point1 = [gesture translationInView:_cView];

translationInView:获取到的是手指移动后,在相对坐标中的偏移量。


-(void)viewDidLoad
{
    [super viewDidLoad];
#pragma mark --------- UIPanGestureRecognizer 拖拽手势 ---------
    
    UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    
    //设置该手势处理器 最少需要 1个手指
    panGesture.minimumNumberOfTouches = 1;
    //设置该手势处理器 最多需要 2个手指
    panGesture.maximumNumberOfTouches = 2;
    
    [_cView addGestureRecognizer:panGesture];
}

#pragma mark ========  UIPanGestureRecognizer 拖拽手势 ======
-(void)handlePan:(UIPanGestureRecognizer *)gesture
{
    //velocityInView :获取该拖动手势在指定控件上的拖动速度**。该方法返回一个 CGPoint结构体数据,该结构体中 `x `变量的值代表了`水平方向的速度`,`y` 变量的值代表了`垂直方向的速度`。
    CGPoint velocity =  [gesture velocityInView:_cView];
    
    //translationInView:获取该拖动手势在指定控件上的位移。该方法返回一个 **CGPoint** 结构体数据,该结构体中 `x` 变量的值代表了`水平方向的位移`,`y` 变量的值代表了`垂直方向的位移`。
     CGPoint translation = [gesture translationInView:_cView];
     
    NSLog(@"水平速度为:%g,垂直速度为:%g, 水平位移为:%g, 垂直位移为:%g",velocity.x,velocity.y,translation.x,translation.y);
                       
}

1.6 、使用 UIScreenEdgePanGestureRecognizer 处理屏幕边缘的拖动手势

UIScreenEdgePanGestureRecognizerUIPanGestureRecognizer 的子类,必须从设置的边缘开发拖动才能触发这个手势。

  UIRectEdgeNone   = 0,
  UIRectEdgeTop    = 1 << 0,
  UIRectEdgeLeft   = 1 << 1,
  UIRectEdgeBottom = 1 << 2,
  UIRectEdgeRight  = 1 << 3,
  UIRectEdgeAll = UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight

苹果在 iOS7以后给导航控制器增加了一个Pop的手势,只要手指在屏幕边缘滑动,当前的控制器的视图就会跟随你的手指移动,当用户松手后,系统会判断手指拖动出来的大小来决定是否要执行控制器的Pop操作。

1.7 、使用 UILongPressGestureRecognizer 处理长按手势

在用户使用一个或多个手指在屏幕上长按、不松开的过程中,程序可通过 UILongPressGestureRecognizer 检测到用户的这种长按手势。

使用 UILongPressGestureRecognizer处理长按手势的步骤与使用其他手势处理器的步骤完全相同。UILongPressGestureRecognizer 定义了如下属性来设置该手势处理器的相关信息。

下面将通过一个实例来示范长按手势处理器的用法。

实例:长按添加按钮

该实例控制 当用户长按屏幕时 添加一个按钮,只要在视图控制器类中为该界面的 UIView 控件添加 UILongPressGestureRecognizer 手势处理器即可,该手势处理器将会检测、处理长按手势。

下面是该控制器类的处理代码:


-(void)viewDidLoad
{
    [super viewDidLoad];
#pragma mark ------- UILongPressGestureRecognizer 长按手势 ---------
    
    //创建一个手势处理器,用于检测、处理长按手势
    UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
        
    [_cView addGestureRecognizer:longPressGesture];
}

#pragma mark --------- UILongPressGestureRecognizer 长按手势 ---------
-(void)handleLongPress:(UILongPressGestureRecognizer*)gesture
{
    //创建一个框
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    [btn setFrame:CGRectMake(100, 100, 100, 100)];
    [btn setTitle:@"长按弹出的视图" forState:UIControlStateNormal];
    [btn setBackgroundColor:[UIColor grayColor]];
    [btn addTarget:self action:@selector(romoveBtn:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
}
-(void)romoveBtn:(UIButton *)btn
{
    [btn removeFromSuperview];
}

1.7、 创建和使用自定义手势处理器

前面介绍的例子都是使用系统内置的手势处理器,但是在一些游戏开发中,程序可能需要检测、处理一些特殊的触摸行为一一系统需要检测用户手指在屏幕上执行某种特殊移动时,程序会做出针对性的响应一此时就需要借助于自定义手势处理器了。

开发自定义手势处理器

开发自定义手势处理器的步骤比较简单,按如下步驟操作即可:

参考文献:https://www.jianshu.com/p/d39f7d22db6c

上一篇 下一篇

猜你喜欢

热点阅读