点击事件传递

参考自:一篇搞定事件传递、响应者链条、hitTest和pointInside的使用

事件的传递,主要是理解UIView两个方法

1.hitTest:withEvent:

2.pointInside:withEvent:


图.1

如图1,绿色(CustomViewB)和黄色(CustomViewC)是黑色(CustomViewA)的子视图,白色(CustomViewD)是黄色的子视图

在每个自定义的视图内重写以下三个方法

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event {

NSLog(@"%s", __func__);

}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

NSLog(@"%s", __func__);

// 是否是可以点击的

if (!self.userInteractionEnabled || self.alpha < 0.01) return nil;

// 判断触摸点是否在自己范围内

if(![self pointInside:point withEvent:event]) return nil;

// 判断是否还有更合适的视图

NSInteger count = self.subviews.count;

for (NSInteger i = (count - 1); i >= 0; i--) {

UIView *childView = self.subviews[i];

CGPoint chindPoint = [self convertPoint:point toView:childView];

UIView *fileView = [childView hitTest:chindPoint withEvent:event];

if (fileView) {

return fileView;

}

}

return self;

}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {

BOOL result = CGRectContainsPoint(self.bounds, point);

NSLog(@"%d-%s",  result, __func__);

return result;

}

一:响应事件分析

1.点击3区域(1,2,4,7区域类似)

2017-06-23 12:42:14.763 sfasd[11534:6414261] -[CustomViewA hitTest:withEvent:]

2017-06-23 12:42:14.763 sfasd[11534:6414261] 1--[CustomViewA pointInside:withEvent:]

2017-06-23 12:42:14.764 sfasd[11534:6414261] -[CustomViewC hitTest:withEvent:]

2017-06-23 12:42:14.764 sfasd[11534:6414261] 1--[CustomViewC pointInside:withEvent:]

2017-06-23 12:42:14.764 sfasd[11534:6414261] -[CustomViewD hitTest:withEvent:]

2017-06-23 12:42:14.765 sfasd[11534:6414261] 0--[CustomViewD pointInside:withEvent:]

2017-06-23 12:42:14.765 sfasd[11534:6414261] -[CustomViewA hitTest:withEvent:]

2017-06-23 12:42:14.765 sfasd[11534:6414261] 1--[CustomViewA pointInside:withEvent:]

2017-06-23 12:42:14.769 sfasd[11534:6414261] -[CustomViewC hitTest:withEvent:]

2017-06-23 12:42:14.773 sfasd[11534:6414261] 1--[CustomViewC pointInside:withEvent:]

2017-06-23 12:42:14.774 sfasd[11534:6414261] -[CustomViewD hitTest:withEvent:]

2017-06-23 12:42:14.774 sfasd[11534:6414261] 0--[CustomViewD pointInside:withEvent:]

2017-06-23 12:42:14.776 sfasd[11534:6414261] -[CustomViewC touchesBegan:withEvent:]

点在3区域,黑色视图先判断点击的点也位于自己的范围内,看看有没有比黑色视图更合适的响应位置,遂倒序遍历自己的子视图;然后黄色视图判断是否在自己的子视图内,发现点击区域位于子视图之外,则没找到更合适的响应视图,只好返回自己;这样一层层的返回,黑色视图返回黄色视图给上一级的视图....最后,最佳的响应视图便是黄色视图,所以[CustomViewC touchesBegan:withEvent:]

2.点击6区域(区域5类似)

2017-06-23 12:55:25.946 sfasd[11534:6414261] -[CustomViewA hitTest:withEvent:]

2017-06-23 12:55:25.947 sfasd[11534:6414261] 1--[CustomViewA pointInside:withEvent:]

2017-06-23 12:55:25.947 sfasd[11534:6414261] -[CustomViewC hitTest:withEvent:]

2017-06-23 12:55:25.947 sfasd[11534:6414261] 0--[CustomViewC pointInside:withEvent:]

2017-06-23 12:55:25.947 sfasd[11534:6414261] -[CustomViewB hitTest:withEvent:]

2017-06-23 12:55:25.948 sfasd[11534:6414261] 0--[CustomViewB pointInside:withEvent:]

2017-06-23 12:55:25.948 sfasd[11534:6414261] -[CustomViewA hitTest:withEvent:]

2017-06-23 12:55:25.948 sfasd[11534:6414261] 1--[CustomViewA pointInside:withEvent:]

2017-06-23 12:55:25.950 sfasd[11534:6414261] -[CustomViewC hitTest:withEvent:]

2017-06-23 12:55:25.950 sfasd[11534:6414261] 0--[CustomViewC pointInside:withEvent:]

2017-06-23 12:55:25.951 sfasd[11534:6414261] -[CustomViewB hitTest:withEvent:]

2017-06-23 12:55:25.952 sfasd[11534:6414261] 0--[CustomViewB pointInside:withEvent:]

2017-06-23 12:55:25.954 sfasd[11534:6414261] -[CustomViewA touchesBegan:withEvent:]

点在6区域,黑色视图先判断点击的点也位于自己的范围内,看看有没有比黑色视图更合适的响应位置,遂倒序遍历自己的子视图;结果都不在自己的子视图内,所以返回自己,[CustomViewA touchesBegan:withEvent:]被调用

结论:1.点击会从父视图倒序遍历自己的自视图,寻找到最合适的响应视图返回;

        2.点击子视图的点超出父视图的范围,子视图无法响应,位于点击的点之下的最近的一个视图会响应事件.


二:点击子视图的点超出父视图的范围无法响应事件的处理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容