事件分三个类型,这里只说触摸事件
- 触摸事件
- 加速计事件
- 远程控制事件
iOS中只有继承于UIResponder的对象才能处理事件,也就是响应者对象,而UIApplication,UIViewController,UIView都是继承于UIResponder
UIResponder提供了四个对象方法来处理事件:
// UIView是UIResponder的子类,可以覆盖下列4个方法处理不同的触摸事件
// 一根或者多根手指开始触摸view,系统会自动调用view的下面方法
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
// 一根或者多根手指在view上移动,系统会自动调用view的下面方法(随着手指的移动,会持续调用该方法)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
// 一根或者多根手指离开view,系统会自动调用view的下面方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
// 触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程,系统会自动调用view的下面方法
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
事件的产生和传递
事件的产生
- 发生触摸事件后,系统会将该事件加入到一个UIApplication管理的事件队列中
- UIApplication会从事件队列中取出最前面的事件,分发下去处理,通常会先把事件发送给应用程序的主窗口(keyWindow)
- 主窗口会在视图层次结构中找到一个最适合的视图处理触摸事件
事件的传递
- 首先判断主窗口是否召集处理事件
- 判断触摸点是否在自身
- 子控件数组中从后往前遍历子控件,然后重复123,直到视图没有子控件符合判断
- 没有符合条件的子控件就是事件响应者
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
/*
寻找事件最适合的view
(不管控件事件能处理事件,是否在触摸点范围内,事件都会传递给这个视图,然后调用hittest方法)
可以通过重写hittest方法来修改响应事件的视图,拦截响应事件
(真实响应者和要修改的响应者都要修改hittest,或者在两者父视图中相应位置返回要修改的响应者,避免真实响应者先执行了hittest方法)
*/
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;
/*
判断事件触摸点是否在视图内,执行hittest方法中会执行此方法
拦截此方法可以用来修改视图点击的响应范围
*/
顺序
事件的传递,从上到下,
UIApplication-UIWindow-UIView-initialView
事件的响应,从下到上
initialView-UIView-UIWindow-UIApplication
系统默认在视图没有实现响应方法的情况下会在touchesBegan中执行[super touchesBegan:touches withEvent:event]方法,将事件往上传递
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
如果要做到一个事件多个视图进行响应,可以修改touchesBegan方法,执行完自定义操作之后,再调用系统的默认做法,再把事件交给上一个响应者处理[super touchesBegan:touches withEvent:event];