使用手势处理器(UIGestureRecognizer)
通过手势处理器处理用户触碰事件更加简单,而且无论处理哪种触碰手势,都可面向 UIGestureRecognizer 编程,UIGestureRecognizer 提供了如下子类。
1、UITapGestureRecognizer:处理用户点击手势的手势处理器。
2、UIPinchGestureRecognizer:处理用户捏合手势的手势处理器。
3、 UIRotationGestureRecognizer:处理用户旋转手势的手势处理器。
4、UISwipeGestureRecognizer:处理用户滑动手势的手势处理器
5、UIPanGestureRecognizer:处理用户拖动手势的手势处理器。
6、UIScreenEdgePanGestureRecognizer:处理用户在屏幕边缘的拖动手势的手势处理器。是 UIPanGestureRecognizer 的一个子类。
7、UILongPressGestureRecognizer:处理用户长按手势的手势处理器。
使用手势处理器处理用户触碰手势的编程步骤如下:
1、根据程序要处理的手势创建对应的手势处理器对象。创建手势处理器时需要指定 target 和 action 参数一一当该控件上发生触碰手势后,该 target 对象的 action 方法将会被激发。
2、如果该 UI 控件不允许用户交互,则将该 UI 控件的
userlnteractionEnabled
属性设为 YES:如果希望该控件可支持多点触碰,还需要将multipleTouchEnabled
设为 YES。3、调用 UI 控件的
addGestureRecognizer
:方法添加该手势处理器。
UIGestureRecognizer 作为所有手势处理器的基类,它提供如下常用的方法和属性:
-locationInView: (UIView*)view
: 返回该手势在 view 控件中的触碰位置。
locationofTouch: (NSUlnteger) touchIndex inView: (UIView*) view
:返回该手势中第 touchIndex 个触碰点在 view 控件中的触碰位置。numberOfTouches
:返回该手势包含触碰点的数量(也就是用户用了几个手指进行触碰
-view
:返回激发该手势的 UI 控件。
enabled
:用于设置和返回该手势处理器是否可用。state
:获取该手势所处的状态,比如手势刚开始时处于UIGestureRecognizerStateBegan
状态,手势结束时处于UIGestureRecognizerStateEnded
状态。
1.1、 使用 UITapGestureRecognizer 处理点击手势
UITapGestureRecognizer 还提供了如下两个属性:
numberOfTapsRequired
:指定该手势处理器只处理几次触碰事件。numberOfTouchesRequired
:指定该手势处理器只处理几个手指的触碰事件。
@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定义了如下两个属性来获取捏合相关信息。
scale
:获取捏合的比例。velocity
:获取捏合的速度.
-(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 定义了如下两个属性来获取旋转相关信息:
rotation
:获取旋转角度velocity
:获取旋转速度
实例:通过 旋转手势 旋转图片
本实例将会对前面的实例进行改进,在前面实例的基础上增加一个旋转手势处理器,从而让该应用既可根据用户捏合手势对图片进行缩放,也可根据用户旋转手势对图片进行旋转。
-(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 定义了如下两个属性来设置相关信息:
direction
:设置该手势处理器处理该方向的轻扫。该属性支持 UISwipeGestureRecognizerDirectionRight (1 << 0) UISwipeGestureRecognizerDirectionLeft (1 <<1) UISwipeGestureRecognizerDirectionUp (1 << 2)
UISwipeGestureRecognizerDirectionDown (1 << 3)
4 个枚举值。numberOfTouchesRequired
:指定该手势处理器只处理几个手指的触碰事件。
下面示例将会示范使用 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 来记录蛇身的每个点。
除此之外,贪食蛇只有两个需要处理的逻辑。
蛇的移动:程序使用一个定时器控制蛇身的移动。对于蛇身的移动来说,蛇头受移动方向的控制,当移动方向为向左时,代表蛇头的点的 X 坐标减 1: 当移动方向为向右时,代表蛇头的点的 X 坐标加 1; 当移动方向为向上时,代表蛇头的点的 Y 坐标减 1 当移动方向为向下时,代表蛇头的点的 Y 坐标加 1。除此之外,蛇身的其他点总是去“追逐”前一个点,也就是将第 i 个点的坐标设置为第 1 个点的坐标。
蛇的方向改变:通过轻扫手势处理器检测用户的轻扫手势,根据轻扫手势的方向来改变蛇的移动方向。
创建一个 Single View Application,该应用将会包含一个应用程序委托类和一个视图控制器类,但程序还需要一个自定义 Uiview 控件类,该控件类负责绘制贪食蛇的游戏界面。
下面是自定义的 FK Snake View 类(该类继承了 Uiview)的接口代码。
贪吃蛇的代码有时间补上
1.5 、使用 UIPanGestureRecognizer 处理拖动手势
在用户使用一个或多个手指在屏幕上拖动的过程中,程序可通过 UIPanGestureRecognizer检测到用户的这种拖动手势。
使用 UIPanGestureRecognizer 处理拖动手势的步骤与使用其他手势处理器的步骤完全相同。UIPanGestureRecognizer 定义了如下两个属性来设置该手势处理器的相关信息:
maximumNumberOfTouches
:设置该拖动手势处理器最多支持几个手指拖动。minimumNumberOfTouches
:设置该拖动手势处理器最少需要几个手指一起拖动。
除此之外,该手势处理器还提供了如下方法来获取拖动相关信息 :
translationInView
:获取该拖动手势在指定控件上的位移。该方法返回一个 CGPoint 结构体数据,该结构体中x
变量的值代表了水平方向的位移
,y
变量的值代表了垂直方向的位移
。velocityInView
:获取该拖动手势在指定控件上的拖动速度。该方法返回一个 CGPoint结构体数据,该结构体中x
变量的值代表了水平方向的速度
,y
变量的值代表了垂直方向的速度
。
下面示例将会示范使用 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 处理屏幕边缘的拖动手势
UIScreenEdgePanGestureRecognizer 是 UIPanGestureRecognizer 的子类,必须从设置的边缘开发拖动才能触发这个手势。
-
edges
:这个属性是边缘拖动手势支持的拖动的位置,默认是没有,不给这个属性赋值的话这个手势是没有意义的。-
UIRectEdgeNone
: 设置为这个值的时候这个手势其实就"失效"了 -
UIRectEdgeTop
: 识别顶部边缘拖动手势 -
UIRectEdgeLeft
:识别左边边缘拖动手势 -
UIRectEdgeBottom
:识别底部边缘拖动手势 -
UIRectEdgeRight
:识别右边边缘拖动手势 -
UIRectEdgeAll
:识别所有方向的边缘拖动手势
-
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 定义了如下属性来设置该手势处理器的相关信息。
minimumPressDuration
:指定用户至少在屏幕上按下多少秒会触发该长按手势。该属性默认值为 0.5。numberOfTouchesRequired
:指定必须使用几个手指在屏幕上长按才会触发该手势。allowableMovement
:指定该长按手势允许用户移动手指的最大距离。如果用户手指按下时移动超过了该距离,则长按手势失效。
下面将通过一个实例来示范长按手势处理器的用法。
实例:长按添加按钮
该实例控制 当用户长按屏幕时 添加一个按钮,只要在视图控制器类中为该界面的 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、 创建和使用自定义手势处理器
前面介绍的例子都是使用系统内置的手势处理器,但是在一些游戏开发中,程序可能需要检测、处理一些特殊的触摸行为一一系统需要检测用户手指在屏幕上执行某种特殊移动时,程序会做出针对性的响应一此时就需要借助于自定义手势处理器了。
开发自定义手势处理器
开发自定义手势处理器的步骤比较简单,按如下步驟操作即可:
- (1)创建继承 UIGestureRecognizer 的子类。
- (2) 重写 UIGestureRecognizer:基类的触碰相关的 4 个方法。通过在这些方法中识别用户手指过的痕迹——当用户手指划过的痕迹符合手势要求时,程序将该手势的
state
设为 UIGestureRecognizerStateEnded 即可。
参考文献:https://www.jianshu.com/p/d39f7d22db6c