iOS事件处理
iOS中的事件以下三种
1. 触摸事件
2. 加速器事件:重力感应,旋转等事件
3. 远程遥控事件:蓝牙线控,耳机线控等
触摸事件
响应者对象
响应者对象是能够响应并处理事件的对象,是构成响应链和事件传递链的节点。
常见的响应者对象有:UIApplication、UIViewController、UIView,都继承自UIResponder。其继承链如下:
responder 继承链
UIResponder的类相关定义如下:
@interface UIResponder : NSObject
- (nullable UIResponder*)nextResponder;
- (BOOL)canBecomeFirstResponder; // default is NO
- (BOOL)becomeFirstResponder;
- (BOOL)canResignFirstResponder; // default is YES
- (BOOL)resignFirstResponder;
- (BOOL)isFirstResponder;
/**** 触摸事件方法,对触摸事件进行处理 *****/
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(nullable NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEstimatedPropertiesUpdated:(NSSet * _Nonnull)touches NS_AVAILABLE_IOS(9_1);
/*** 加速器事件方法,对其进行处理 ***/
- (void)motionBegan:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
- (void)motionEnded:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
/*** 遥控事件方法 ***/
- (void)remoteControlReceivedWithEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(4_0);
@end
从UIResponder类中可以看到,需要处理触摸,加速器和遥控等事件时需要重写响应的方法,对UITouch和UIEvent进行处理。
UITouch对象是一个手指接触到屏幕并在屏幕上移动或离开屏幕时创建的。它有几个属性和实例方法:
phase:属性,返回一个阶段常量,指出触摸开始、继续、结束或被取消,是一个枚举配型,包含了
·UITouchPhaseBegan(触摸开始)
·UITouchPhaseMoved(接触点移动)
·UITouchPhaseStationary(接触点无移动)
·UITouchPhaseEnded(触摸结束)
·UITouchPhaseCancelled(触摸取消)
tapCount:属性,轻按屏幕的次数
timeStamp:属性,触摸发生的时间
view:属性,触摸始于那个视图
window:属性,触摸始于哪个窗口
lacationInView:方法,触摸在指定视图中的当前位置
previousLocationView:方法,触摸在指定视图中的前一个位置
UIEvent对象包含一组相关的UITouch对象,由UITouch对象组成UIEvent对象,可以理解成一个完整的触摸操作是一个UIEvent,而这一系列完整操作中的每个点就是UITouch(按下、移动、离开)。
UIEvent的作用是提供相关触摸操作的列表,如果要获取在屏幕上触摸的手势,可以使用该对象,这一些列操作都存储在Foundation框架中的NSSet对象中。
响应链
当触摸事件发生时,必须知道有谁来响应事件,所以会进行一个事件响应的一个传导,这就叫做响应链。
每一个应用有一个响应者链,我们的视图结构是一个N叉树(一个视图可以有多个子视图,一个子视图同一时刻只有一个父视图),而每一个继承UIResponder的对象都可以在这个N叉树中扮演一个节点。当叶节点成为最高响应者的时候,从这个叶节点开始往其父节点开始追朔出一条链,那么对于这一个叶节点来讲,这一条链就是当前的响应者链。响应者链将系统捕获到的UIEvent与UITouch从叶节点开始层层向下分发,期间可以选择停止分发,也可以选择继续向下分发。
事件响应链从图中可以看到,响应者链有以下特点:
- 响应者链通常是由 initial view 开始;
- UIView的nextResponder它的superview;如果UIView已经是其所在的 UIViewController的top view, 那么UIView的nextResponder 就是UIViewController;
- UIViewController 如果有 Super ViewController,那么它的 nextResponder 为其 Super ViewController 最表层的 View;如果没有,那么它的 nextResponder 就是 UIWindow;
- UIWindow 的 contentView 指向 UIApplication,将其作为 nextResponder;
- UIApplication 是一个响应者链的终点,它的 nextResponder 指向nil,整个 responder chain 结束。
所有事件响应的类都是UIResponder的子类,响应者链是一个由不同对象组成的层次结构,其中的每个对象将依次获得响应事件消息的机会。当发生事件时,事件首先被发送给第一响应者,第一响应者往往是事件发生的视图,也就是用户触摸屏幕的地方。事件将沿着响应者链一直向下传递,直到被接受并做出处理。
一个典型的响应链路线图如下:
initial view –> super view –> …..–> view controller –> window –> Application –> AppDelegate
hitTest
当用户与 iPhone 的触摸屏产生互动时,硬件就会探测到物理接触并且通知操作系统。操作系统就会创建相应的事件,并将其传递给当前正在运行的应用程序的事件队列。然后这个事件会被事件循环传递给优先响应对象,即 Hit-Test View 。
Hit-Test View 就是事件被触发时和用户交互的对象,寻找 Hit-Test View 的过程就叫做 Hit-Testing。
参考文章:
深入浅出iOS事件机制
Responder一点也不神秘——iOS用户响应者链完全剖析
iOS Events and Responder Chain