iOS学习23之事件处理
1. 事件的基本概念
1> 概述
事件是当用户手指触击屏幕及在屏幕上移动时,系统不断发送给应用程序的对象。
系统将事件按照特定的路径传递给可以对其进行处理的对象
在iOS中,一个UITouch对象表示一个触摸,一个UIEvent对象表示一个事件。事件对象中包含与当前多点触摸序列相对应的所有触摸对象,还可以提供与特定视图或窗口相关联的触摸对象。
2> 事件类型
2. 触摸的基本概念
1> 概述
触摸信息有时间和空间两方面。
时间方面的信息称为阶段(phrase),表示触摸是否刚刚开始、是否正在移动或处处于静止状态,以及何时结束—--也就是手指何时从屏幕抬起。
空间方面是指当前在视图或窗口中的位置信息,以及之前的位置信息(如果有的话)。当一个手指接触屏幕时, 触摸就和某个窗口或视图关联在一起,这个关联在事件的整个生命周期都会得到维护。
2> 触摸事件的阶段
3> 触摸事件的处理方法
在给定的触摸阶段中,如果发生新的触摸动作或已有的触摸动作发生变化,应用程序就会发送这些消息:
当一个或多个手指触碰屏幕时,发送touchesBegan:withEvent:消息。
1 // 触摸开始 2 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 3 { 4 NSLog(@"触摸TouchView开始"); 5 }
当一个或多个手指在屏幕上移动时,发送touchesMoved:withEvent:消息。
1 // 移动 2 - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 3 { 4 NSLog(@"移动TouchView"); 5 6 // 1.获取触摸手势 7 UITouch *touch = [touches anyObject]; 8 9 // 2.获取触摸的位置 10 // locationInView: 获取一个触摸在某个视图上的位置 11 CGPoint currentPoint = [touch locationInView:self.superview]; 12 13 // 3.根据触摸的位置改变视图的位置 14 self.center = currentPoint; 15 16 }
当一个或多个手指离开屏幕时,发送touchesEnded:withEvent:消息。
1 // 触摸结束 2 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 3 { 4 NSLog(@"触摸TouchView结束"); 5 }
当触摸被打断时,发送touchesCancelled:withEvent:消息
1 // 触摸被打断 2 - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 3 { 4 NSLog(@"触摸TouchView被打断"); 5 }
3. 响应者链
1> 概述
响应者链是一个响应者对象的连接序列,事件或动作消息(或菜单编辑消息)依次传递。
它允许响应者对象把事件处理的职责转交给其它更高层的对象。
应用程序通过向上传递一个事件来查找合适的处理对象。因为点击检测视图也是一个响应者对象,应用程序在处理触摸事件时也可以利用响应链。
由多个响应者对象组成的链。
2> 响应者
iOS中所有能响应事件(触摸、晃动、远程事件)的对象都是响应者。
系统定义了一个抽象的父类UIResponder来表示响应者。其子类都是响应者。
3> 检测视图
硬件检测到触摸操作,会将信息交给UIApplication,开始检测。
顺序(从最下层开始向上):UIApplication -> window -> viewController -> view -> 检测所有视图
最终确认触碰位置,完成响应者链的查询过程。
4> 处理触摸事件
检测到响应者后,实现touchesBegan:withEvent:等方法,即处理事件。
如果响应者没有处理事件,事件会向下传递。如果没有响应者处理,则丢弃触摸事件。
事件处理的顺序与触摸检测查询相反。
触摸的子视图 -> view -> viewController -> window -> UIApplication
5> 阻断响应者链
响应者链可以被打断,无法完成检测查询过程。
视图类的属性 : userInteractionEnabled,关闭后能阻断查询过程,即值为NO时,从当前视图开始到所有的子视图不再检测。
6> 响应者链处理原则
-
点击检测视图或者第一响应者传递事件或动作消息给它的视图控制器(如果它有的话);如果没有一个视图控制器,就传递给它的父视图。
-
如果一个视图或者它的视图控制器不能处理这个事件或动作消息,它将传递给该视图的父视图。
-
在这个视图层次中的每个后续的父视图遵循上述的模式。
-
最顶层的视图如果不能处理这个事件或动作消息,就传递给UIWindow对象来处理。
-
如果UIWindow对象不能处理,就传给单件应用程序对象UIApplication,如果应用程序对象也不能处理这个事件或动作消息,将抛弃它。
4. 手势
1> 概述
手势识别器是对触摸事件做了封装,手势识别器本身起到了识别作用
手势识别器是iOS中比较抽象的一个类,用于识别一个手势,所谓手势:有规律的触摸。
2> 手势分类
3> 手势识别器
系统提供的手势识别器这个抽象父类我们是不会直接使用的,而是根据需求使用特定的手势识别器创建对象,系统所提供的手势类型如下所示:(需要将下面的方法在viewDidLoad方法中调用才能实现)
① UITapGestureRecognizer是轻拍手势识别器,能识别轻拍操作
1 // 创建一个轻拍手势方法 2 - (void)tapGesture 3 { 4 // 1.创建手势识别器对象 5 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureAction:)]; 6 7 // 2.将手势添加到相应的视图上 8 [self.rootView.myImageView addGestureRecognizer:tap]; 9 } 10 11 // 实现轻拍手势事件 12 - (void)tapGestureAction:(UITapGestureRecognizer *)tap 13 { 14 NSLog(@"被拍了!"); 15 }
② UIPanGestureRecognizer是平移手势识别器,能识别拖拽操作
1 // 创建一个平移手势方法 2 - (void)panGesture 3 { 4 UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureAction:)]; 5 6 [self.rootView.myImageView addGestureRecognizer:pan]; 7 } 8 9 // 实现平移手势事件 10 - (void)panGestureAction:(UIPanGestureRecognizer *)pan 11 { 12 NSLog(@"我动了..."); 13 14 // 在View上面挪动的距离,translationInView是用来获取触摸移动的距离 15 CGPoint p = [pan translationInView:pan.view]; 16 17 pan.view.transform = CGAffineTransformTranslate(pan.view.transform, p.x, p.y); // pan.view.transform 表示视图原来的位置,p.x表示移动的X轴方向的距离,p.y表示移动的Y轴方向的距离 18 19 // 清空移动的距离 20 [pan setTranslation:CGPointZero inView:pan.view];
③ UIPinchGestureRecognizer是捏合手势识别器,能识别捏合操作
1 - (void)pinchGesture 2 { 3 UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGestureAction:)]; 4 [self.rootView.myImageView addGestureRecognizer:pinch]; 5 } 6 7 // 实现捏合方法 8 - (void)pinchGestureAction:(UIPinchGestureRecognizer *)pinch 9 { 10 pinch.view.transform = CGAffineTransformScale(pinch.view.transform, pinch.scale, pinch.scale); 11 pinch.scale = 1; // 清空移动的比例 12 }
④ UIRotationGestureRecognizer是旋转手势识别器,能识别旋转操作
1 // 创建一个旋转手势方法 2 - (void)rotattionGesture 3 { 4 UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotattionGestureAction:)]; 5 6 [self.rootView addGestureRecognizer:rotation]; 7 } 8 9 // 实现旋转手势事件 10 - (void)rotattionGestureAction:(UIRotationGestureRecognizer *)rotation 11 { 12 rotation.view.transform = CGAffineTransformRotate(rotation.view.transform, rotation.rotation); // rotation的旋转角度是rotation属性 13 rotation.rotation = 0; 14 }
⑤ UILongPressGestureRecognizer是长按手势识别器,能识别长按操作
1 // 创建一个长按手势方法 2 - (void)longPress 3 { 4 UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressAction:)]; 5 [self.rootView.myImageView addGestureRecognizer:longPress]; 6 } 7 8 // 实现长按手势事件 9 - (void)longPressAction:(UILongPressGestureRecognizer *)longPress 10 { 11 if (longPress.state == UIGestureRecognizerStateBegan) { 12 // 设置长按的时间 13 longPress.minimumPressDuration = 2; 14 NSLog(@"长按了..."); 15 } 16 }
⑥ UISwipeGestureRecognizer是轻扫手势识别器,能识别拖拽操作
1 // 创建一个轻扫手势方法 2 - (void)swipe 3 { 4 UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeAction:)]; 5 6 // 设置轻扫的有效方向 7 swipe.direction = UISwipeGestureRecognizerDirectionLeft; // 默认为Right(右) 8 9 // 手指的数量 10 // swipe.numberOfTouchesRequired = 2; // 默认为1 11 12 [self.rootView.myImageView addGestureRecognizer:swipe]; 13 } 14 15 // 实现轻扫手势事件 16 - (void)swipeAction:(UISwipeGestureRecognizer *)swipe 17 { 18 NSLog(@"向左扫了一下!"); 19 }
⑦ UIScreenEdgePanGestureRecognizer是屏幕边缘轻扫识别器
1 // 创建一个屏幕边缘清扫方法 2 - (void)screenEdgePan 3 { 4 UIScreenEdgePanGestureRecognizer *screenEdgePan = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(screenEdgePanAction:)]; 5 6 screenEdgePan.edges = UIRectEdgeLeft; // 所有的 7 8 [self.rootView addGestureRecognizer:screenEdgePan]; 9 } 10 // 实现屏幕边缘清扫事件 11 - (void)screenEdgePanAction:(UIScreenEdgePanGestureRecognizer *)screenEdgePan 12 { 13 NSLog(@"屏幕左边缘清扫"); 14 }
4> 手势识别器使用步骤小结
- 创建UIxxxGestureRecognizer对象,使用initWithTarget:action:方法
-
配置要识别的手势相关信息
-
将手势添加到某个视图上
-
实现手势识别器里定义的方法
5> View的transform属性
transform是view的一个重要属性,他在矩阵层面上改变view的显示状态,能实现view的缩放 , 旋转 , 平移等功能
平移 CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty) t --- 表示视图原来的位置, tx --- 移动的X轴方向的距离, ty --- 移动的Y轴方向的距离
具体使用方法见 3> ② 的代码
缩放 CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy) t --- 表示视图原来的位置, tx --- 缩放的X轴方向的比例, ty --- 缩放的Y轴方向的比例 具体使用方法见 3> ③ 的代码
旋转 CGAffineTransformRotate(CGAffineTransform t, CGFloat angle) t --- 表示视图原来的位置 , angle --- 表示旋转角度 具体使用方法见 3> ④ 的代码
6> 通过代理实现同时识别多个手势
① 在需要的多个手势中设置代理
xxx.delegate = self;
② 遵循协议 UIGestureRecognizerDelegate
③ 实现代理方法来实现同时识别多个手势
1 #pragma mark 通过代理实现同时识别多个手势 2 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 3 { 4 return YES; 5 }