响应链是由一系列链接在一起的响应者组成的,一般 情况下,一条响应链开始于第一响应者,结束于appliaction对象,如果一个响应者不能处理事件 ,则会将事件沿着响应链传到下一个响应者 响应者:(UIResponse子类:UIApplication、UIViewController、UIView)
事件传递
事件传递:寻找事件的第一响应者 当一个事件发生后,事件会由父控件传给子控件 硬件 -> 系统 -> UIApplication -> UIWindow -> SuperView -> SubView 以上就是事件的传递 符合第一响应者的条件:
- touch事件的位置在响应者区域内 pointInside:withEvent: == YES
- 响应者 self.hidden != NO
- 响应者 self.alpha > 0.01
- 响应者 self.userInteractionEnabled = YES 第一响应者对于接收到的事件有3种操作:
- 不拦截,默认操作。事件会自动沿着默认的响应链往下传递
- 拦截,不再往下分发事件。重写 touchesBegan:withEvent: 进行事件处理,不调用父类的 touchesBegan:withEvent:
- 拦截,继续往下分发事件。重写 touchesBegan:withEvent: 进行事件处理,同时调用父类的 touchesBegan:withEvent: 将事件往下传递
事件响应
事件的响应是从下到上(顺着响应者链条向上传递:子控件到父控件。
- 首先由 view 来尝试处理事件,如果他处理不了,事件将被传递到他的父视图 superview
- superview 也尝试来处理事件,如果他处理不了,继续传递他的父视图 UIViewcontroller.view
- UIViewController.view 尝试来处理该事件,如果处理不了,将把该事件传递给 UIViewController
- UIViewController 尝试处理该事件,如果处理不了,将把该事件传递给主窗口 Window
- 主窗口 Window 尝试来处理该事件,如果处理不了,将传递给应用单例 Application
- 如果 Application 也处理不了,则该事件将会被丢弃
案例
子视图超出父视图不响应事件
//判断点是否在空间上用到
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
// 将像素point由point所在视图转换到目标视图view中,返回在目标视图view中的像素值
- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view;
// 将像素point从view中转换到当前视图中,返回在当前视图中的像素值
- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view;
touch事件传递
//TestView
#import "TestView.h"
#import "TestView2.h"
@interface TestView()
@property(nonatomic,strong)TestView2 *view2;
@end
@implementation TestView
-(instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
self.view2 = [[TestView2 alloc]initWithFrame:CGRectMake(50, 50, 100, 100)];
self.view2.backgroundColor = [UIColor orangeColor];
[self addSubview:self.view2];
}
return self;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"++++");
}
@end
#import "TestView2.h"
@implementation TestView2
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"-----");
}
@end
当我们点击testView2的时候,发现输出了----- ,但是我们想着testView2,是testView的子视图,当点击testView2的时候,父视图也要响应,这时候,只需在TestView2的touchesBegan事件内,将这个事件转发下去即可,这时候父视图也可以响应事件
#import "TestView2.h"
@implementation TestView2
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
NSLog(@"-----");
}
@end