事件传递和响应机制

iOS中的事件

1.事件的生命周期

事件的生命周期从事件的产生和传递(事件如何从父控件传递到子控件并寻找到最合适的view、寻找最合适的view的底层实现、拦截事件的处理)->事件的响应(找到最合适的view后对事件进行处理,touches方法的重写)

2.事件的分类

iOS中的事件可以分为3大类型:

  • 触屏事件(例如点击按钮、通过手势缩放图片、拖动上下滚动页面等)
  • 传感器事件(例如摇一摇红包、通过旋转设备控制赛车方向、指南针等)
  • 远程控制事件(例如耳机的线控、外接手柄、遥控器等)

3.响应者对象(UIResponder)

在iOS中只有继承了UIResponder的对象才能接收和处理事件,UIResponder的子类包括UIView,UIViewController,UIApplication等。响应者接收到原始事件数据,必须处理事件转发到另一个响应者对象,当APP接收到一个事件事,UIKit自动引导事件到最合适的的响应者对象,也叫做第一响应者。
UIResponder内部提供了以下方法来处理事件

触摸事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
加速计事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
远程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;

4.事件中的概念

在自定义UIView为属性的控件时可以重写触摸事件的方法来进行点击回调。在回调中可以看到方法接收两个参数,一个是UITouch对象的集合,还有一个是UIEvent对象。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    NSLog(@"触摸开始--touches:%@,event:%@",touches,event);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
    NSLog(@"开始移动--touches:%@,event:%@",touches,event);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    NSLog(@"触摸结束--touches:%@,event:%@",touches,event);
}
//只有在程序强制退出或者来电时才会调用
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
    NSLog(@"触摸取消--touches:%@,event:%@",touches,event);
}

4.1UIEvent

表示用户交互的事件对象,每产生一个事件,就会产生一个UIEvent对象。在一个用户点击事件处理过程中,UIEvent对象是唯一的。
UIEvent属性如下:

//事件类型
@property(nonatomic,readonly) UIEventType     type NS_AVAILABLE_IOS(3_0);
@property(nonatomic,readonly) UIEventSubtype  subtype NS_AVAILABLE_IOS(3_0);
//事件产生时间
@property(nonatomic,readonly) NSTimeInterval  timestamp;

4.2UITouch

当用户用一根手指触摸屏幕时,会创建一个与手指相关的UITouch对象 ,一根手指对应一个UITouch对象。
UITouch属性如下:

//触摸产生时所处的窗口
@property(nonatomic,readonly,retain) UIWindow *window;
//触摸产生时所处的视图
@property(nonatomic,readonly,retain) UIView *view
;
//短时间内点按屏幕的次数,可以根据tapCount判断单击、双击或更多的点击
@property(nonatomic,readonly) NSUInteger tapCount;
//记录了触摸事件产生或变化时的时间,单位是秒
@property(nonatomic,readonly) NSTimeInterval timestamp;
//当前触摸事件所处的状态
@property(nonatomic,readonly) UITouchPhase phase;

UITouch方法如下:

// 返回值表示触摸在view上的位置
// 这里返回的位置是针对view的坐标系的(以view的左上角为原点(0, 0))
// 调用时传入的view参数为nil的话,返回的是触摸点在UIWindow的位置
(CGPoint)locationInView:(UIView *)view;
// 该方法记录了前一个触摸点的位置
(CGPoint)previousLocationInView:(UIView *)view;

事件的传递和响应

1.事件的产生和传递

1.1事件的产生

1.发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的队列事件中
2.UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常会先发送事件给应用程序的主窗口(keyWindow)
3.主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件

1.2事件的传递

触摸事件的传递是从父控件传递到子控件。事件传递给窗口或者控件后,就调用hitTest:withEvent:方法寻找更合适的view。方法底层会调用pointInside:withEvent:方法判断点在不在方法调用者的坐标系上,如果返回YES说明点在当前view上,继续通过hitTest:withEvent:方法遍历子控件,直到找到最合适的view。如返回NO,代表事件不在view内,直接返回nil,说明当前view不是最合适的view,其以下的子控件也都会被忽略。
这个方法会忽略以下情况:

  • 视图是隐藏的 hidden = YES
  • 用户交互是关闭的 userInteractionEnabled = NO
  • 透明度小于0.01的 alpha < 0.01

2.事件的响应

  • 响应者链条
    在ios程序中每个控件的摆放是有前后关系的,这种先后关系构成的一个链条就叫响应者链。
  • 响应者链的事件传递过程
    1.如果当前view是控制器的view,那么控制器就是上一个响应者,事件就传递给控制器;如果当前view不是控制器的view,那么父视图就是当前view的上一个响应者,事件就传递给它的父视图
    2.在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理
    3.如果window对象也不处理,则其将事件或消息传递给UIApplication对象
    4.如果UIApplication也不能处理该事件或消息,则将其丢弃

你可能感兴趣的:(事件传递和响应机制)