01-iOS事件介绍
- UIEvent
- 每产生一个事件,就会产生一个UIEvent对象
- UIEvent:称为事件对象,记录事件产生的时刻和类型
- 常见属性
- 事件类型
@property(nonatomic,readonly) UIEventType type;
@property(nonatomic,readonly) UIEventSubtype subtype;
/*
typedef
NS_ENUM(NSInteger, UIEventType) {
UIEventTypeTouches,
UIEventTypeMotion,
UIEventTypeRemoteControl,
};
typedef
NS_ENUM(NSInteger, UIEventSubtype) {
// available in iPhone OS 3.0
UIEventSubtypeNone = 0,
// for UIEventTypeMotion, available in iPhone OS 3.0
UIEventSubtypeMotionShake = 1,
// for UIEventTypeRemoteControl, available in iOS 4.0
UIEventSubtypeRemoteControlPlay = 100,
UIEventSubtypeRemoteControlPause = 101,
UIEventSubtypeRemoteControlStop = 102,
UIEventSubtypeRemoteControlTogglePlayPause = 103,
UIEventSubtypeRemoteControlNextTrack = 104,
UIEventSubtypeRemoteControlPreviousTrack = 105,
UIEventSubtypeRemoteControlBeginSeekingBackward = 106,
UIEventSubtypeRemoteControlEndSeekingBackward = 107,
UIEventSubtypeRemoteControlBeginSeekingForward = 108,
UIEventSubtypeRemoteControlEndSeekingForward = 109,
};
*/
- 事件产生的时间
@property(nonatomic,readonly) NSTimeInterval timestamp;
- UIEvent还提供了相应的方法可以获得在某个view上面的触摸对象(UITouch)
UIResponder
- 响应者对象
- 在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件。我们称之为“响应者对象”
- UIApplication、UIViewController、UIView都继承自UIResponder,因此它们都是响应者对象,都能够接收并处理事件
UIResponder处理事件方法
UIResponder
- UIResponder内部提供了以下方法来处理事件
- 触摸事件
- (void)touchesBegan:(NSSet *)toucheswithEvent:(UIEvent *)event;
- 手指按下
- (void)touchesMoved:(NSSet *)toucheswithEvent:(UIEvent *)event;
- 手指移动
- (void)touchesEnded:(NSSet *)toucheswithEvent:(UIEvent *)event;
- 手指抬起
- (void)touchesCancelled:(NSSet *)toucheswithEvent:(UIEvent *)event;
- 意外中断事件(电话打扰)
- 加速计事件
- (void)motionBegan:(UIEventSubtype)motionwithEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motionwithEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motionwithEvent:(UIEvent *)event;
- 远程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;
UIView和UIResponder
- UIView是UIResponder的子类,可以覆盖下列4个方法处理不同的触摸事件
- (void)touchesBegan:(NSSet*)touches wi thEvent:(UIEvent *)event
- 一根或者多根手指开始触摸view,系统会自动调用view的下面方法
- (void)touchesMoved:(NSSet *)toucheswithEvent:(UIEvent *)event
- 一根或者多根手指在view上移动,系统会自动调用view的下面方法(随着手指的移动,会持续调用该方法)
- (void)touchesEnded:(NSSet *)toucheswithEvent:(UIEvent *)event
- 一根或者多根手指离开view,系统会自动调用view的下面方法
- (void)touchesCancelled:(NSSet *)toucheswithEvent:(UIEvent *)event
- 触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程,系统会自动调用view的下面方法
提示:touches中存放的都是UITouch对象
UITouch
- UITouch介绍
- 当用户用一根手指触摸屏幕时,会创建一个与手指相关联的UITouch对象
- 一根手指对应一个UITouch对象
- UITouch的作用
- 保存着跟本次手指触摸相关的信息,比如触摸的位置、时间、阶段
- 当手指移动时,系统会更新同一个UITouch对象,使之能够一直保存该手指在的触摸位置
- 当手指离开屏幕时,系统会销毁相应的UITouch对象
- 提示:iPhone开发中,要避免使用双击事件!
触摸事件处理的详细过程
- 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中
- UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)
- 主窗口会调用hitTest:withEvent:方法在视图(UIView)层次结构中找到一个最合适的视图来处理触摸事件,但是这仅仅是整个事件处理过程的第一步
- 找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理
- touchesBegan…
- touchesMoved…
- touchedEnded…
- 这些touches方法的默认做法是将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理
响应者链的事件传递过程:
- 如果view的控制器存在,就传递给控制器;如果控制器不存在,则将其传递给它的父视图;
- 在视图层次结构最顶级的视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理。
- 如果window对象也不处理,则其将事件或消息传递给UIApplication对象;
- 如果UIApplication也不能处理该事件或消息,则将其丢弃。
- 具体流程:
在事件的产生和传递的过程中涉及到的方法
-
- hitTest:withEvent:方法大致处理流程:
- 首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内:
- 若pointInside:withEvent:方法返回NO,说明触摸点不在当前视图内,则当前视图的hitTest:withEvent:返回nil
- 若pointInside:withEvent:方法返回YES,说明触摸点在当前视图内,则遍历当前视图的所有子视图(subviews),调用子视图的hitTest:withEvent:方法重复前面的步骤,子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图的hitTest:withEvent:方法返回非空对象或者全部子视图遍历完毕:
- 若第一次有子视图的hitTest:withEvent:方法返回非空对象,则当前视图的hitTest:withEvent:方法就返回此对象,处理结束
- 若所有子视图的hitTest:withEvent:方法都返回nil,则当前视图的hitTest:withEvent:方法返回当前视图自身(self)
- 最终,这个触摸事件交给主窗口的hitTest:withEvent:方法返回的视图对象去处理。
- 拿到这个UIView后,就调用该UIView的touches系列方法。
- 模拟hitTest方法实现
- hitTest:withEvent:方法大致处理流程:
UIView不接收触摸事件的三种情况
- 不接收用户交互:userInteractionEnabled = NO
- 隐藏:hidden = YES
- 透明:alpha = 0.0 ~ 0.01
提示:UIImageView的userInteractionEnabled默认就是NO,因此UIImageView以及它的子控件默认是不能接收触摸事件的