响应链&事件传递
2020-10-22 本文已影响0人
灰溜溜的小王子
先上图![]()
再上代码:
重要的是两个方法:
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event ;
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event ;
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor orangeColor];
self.btn = [UIButton buttonWithType:UIButtonTypeCustom];
self.btn.frame = CGRectMake(150, 150, 100, 100);
self.btn.backgroundColor = [UIColor redColor];
[self addSubview:self.btn];
[self.btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
-(void)layoutSubviews{
[super layoutSubviews];
}
-(void)btnClick{
NSLog(@"btnClick");
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
// 如果控件不允许与用用户交互,那么返回nil
NSLog(@"%@",event);
if (!self.userInteractionEnabled || [self isHidden] || self.alpha <= 0.01) {
return nil;
}
// NSLog(@"%f----%f",point.x,point.y);
//判断当前视图是否在点击范围内
if ([self pointInside:point withEvent:event]) {
//遍历当前对象的子视图(倒序)
__block UIView *hit = nil;
[self.subviews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//坐标转换,把当前坐标系上的点转换成子控件坐标系上的点
CGPoint convertPoint = [self convertPoint:point toView:obj];
//调用子视图的hitTest方法,判断自己的子控件是不是最适合的View
hit = [obj hitTest:convertPoint withEvent:event];
//如果找到了就停止遍历
if (hit)
*stop = YES;
}];
//返回当前的视图对象
return hit?hit:self;
}else {
return nil;
}
return nil;
}
// 该方法判断触摸点是否在控件身上,是则返回YES,否则返回NO,point参数必须是方法调用者的坐标系
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
CGFloat x1 = point.x;
CGFloat y1 = point.y;
if ((x1 > 150 && x1 < 250) && (y1 > 150 && y1 < 750)) {
return YES;
}else{
return NO;
}
}

说明:
橙色视图中间添加红色视图;
1.没有两个方法的情况下,在红色视图与橙色交界的范围可响应点击事件;
2.加上如上方两个系统方法处理的条件下,整个红色视图及之外的往下一点儿也可以响应点击事件。
参考:事件传递&响应链