一看就懂的iOS触摸事件

本文详细解析了iOS中触摸事件的处理流程及手势识别机制,包括触摸事件如何被分发给视图、响应链的工作原理,以及各种常用手势的识别状态与处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.触摸事件处理

iOS程序启动后UIApplication会循环监听用户操作,当有触摸操作时,触摸事件会被添加到UIApplication事件队列,
UIApplication会从事件队列取出最前面的事件并分发处理,通常先分发给应用程序主窗口,主窗口会
调用hitTest:withEvent:方法(UIView的方法),查找合适的事件触发视图
  1. 在顶级视图(key window的视图)上调用pointInside:withEvent:方法判断触摸点是否在当前视图内;
  2. 如果返回NO,那么A返回nil;
  3. 如果返回YES,那么它会向当前视图的所有子视图(key window的子视图)发送hitTest:withEvent:消息,遍历所有子视图的顺序是从subviews数组的末尾向前遍历(从界面最上方开始向下遍历)。
  4. 如果有subview的hitTest:withEvent:返回非空对象则A返回此对象,处理结束(注意这个过程,子视图也是根据pointInside:withEvent:的返回值来确定是返回空还是当前子视图对象的。并且这个过程中如果子视图的hidden=YES、userInteractionEnabled=NO或者alpha小于0.1都会并忽略);
  5. 如果所有subview遍历结束仍然没有返回非空对象,则A返回顶级视图;
找到了事件触发视图,怎么处理事件呢?iOS中存在一个称为响应链的处理流程,什么是响应链呢?iOS中的控件摆放的时候是有前后关系的,一个控件可以在另一个控件的上面或下面,那么用户点击的时候是触发上面的控件还是触发下面的控件呢,这种先后关系构成一个链条就叫“响应者链”。在iOS中响应者链的关系可以用下图(官方文档中的图)表示
当一个事件发生后首先看initial view(事件触发所在视图)能否处理这个事件,如果不能则会将事件传递给其上级视图(inital view的superView);如果上级视图仍然无法处理则会继续往上传递;一直传递到视图控制器view controller,首先判断视图控制器的根视图view是否能处理此事件;如果不能则接着判断该视图控制器能否处理此事件,如果还是不能则继续向上传递;(对于第二个图视图控制器本身还在另一个视图控制器中,则继续交给父视图控制器的根视图,如果根视图不能处理则交给父视图控制器处理);一直到window,如果window还是不能处理此事件则继续交给application(UIApplication单例对象)处理,如果最后application还是不能处理此事件则将其丢弃。

!!!以下几种情况不能处理触摸事件:
1.userInteractionEnabled=NO 
2.hidden=YES 
3.alpha=0~0.01
        注意!!!
UIResponse的子类都能对触摸事件进行处理,
处理方法如:
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
这些处理方法的默认实现是将事件传递给响应链的下一个,如果我们实现了其中一个事件处理方法,
但没有把它传递给它的下一个响应链,那么下面的响应链都不会处理该事件,例如我们实现了当前View的触摸开始处理方法,
但没有将事件传给下一个响应者,那么下一个相应者不能处理触摸开始事件。

2.手势识别

iOS的手势识别功能真的是太赞了,一共有六中常用手势:
 
 
常用属性

常用方法


在iOS中手势有不同的状态,我们可以根据不同状态做不同的处理
typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
	// 尚未识别是何种手势操作(但可能已经触发了触摸事件),默认状态
	UIGestureRecognizerStatePossible, 
	// 手势已经开始,此时已经被识别,但是这个过程中可能发生变化,手势操作尚未完成 
	UIGestureRecognizerStateBegan, 
	UIGestureRecognizerStateChanged, // 手势状态发生转变
	UIGestureRecognizerStateEnded, // 手势识别操作完成(此时已经松开手指)
	UIGestureRecognizerStateCancelled, // 手势被取消,恢复到默认状态
	UIGestureRecognizerStateFailed, // 手势识别失败,恢复到默认状态
	// 手势识别完成,同UIGestureRecognizerStateEnded
	UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded 
	};


下面解释下为什么要定义状态枚举
对于离散型手势(既简单手势)UITapGestureRecgnizer要么被识别,要么失败,点按(假设点按次数设置为1,并且没有添加长按手势)下去一次不松开则此时什么也不会发生,松开手指立即识别并调用操作事件,并且状态为3(已完成)。 
但是连续手势要复杂一些,就拿旋转手势来说,如果两个手指点下去不做任何操作,此时并不能识别手势(因为我们还没旋转)但是其实已经触发了触摸开始事件,此时处于状态0;如果此时旋转会被识别,也就会调用对应的操作事件,同时状态变成1(手势开始),但是状态1只有一瞬间;紧接着状态变为2(因为我们的旋转需要持续一会),并且重复调用操作事件(如果在事件中打印状态会重复打印2);松开手指,此时状态变为3,并调用1次操作事件。
使用手势
手势识别这么好玩这么强大,那么我们该怎么使用呢,大概有以下几步就搞定了:
----->创建对应的手势对象; 
---->设置手势识别属性【可选】; 
---->把手势添加到指定的对象; 
---->编写手势处理方法;

解决手势冲突
手势这么多,有时候我们可能给一个控件添加了多个手势,不同的手势响应不同的处理,
如果一个手势A的识别部分是另一个手势B的子部分时,默认情况下A就会先识别,B就无法识别了。
要解决这个冲突可以利用
- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;
方法来完成。

   
















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值