点击事件处理

  • 发送触摸时间后,系统会将事件添加到系统UIApplication的事件管理队列中
  • UIApplication 会在事件队列的最前端取出事件,然后分发下去,通常会把事件分发给KeyWindow处理
  • KeyWindow 会在视图层次中 找到一个最合适的视图来处理触摸事件,这也是处理事件过程的第一步
  • 找到合适的视图后,就会调用视图控件响应的方法
  • 如果父控件不能接受事件,那么子控件就不能接受事件

当用户点击屏幕后,UIApplication 先响应事件,然后传给UIWindow,如果window可以响应。就开始遍历window的subViews. 遍历的过程中,如果第一个遍历的View1可以响应,那就遍历这个 View1的 subviews(依次不停的查找,直到找到合适的响应事件View)。如果View1 不可以响应,那就开始对view2进行判断和子视图遍历。如果最后没有找到合适的响应view,这个消息就会被抛弃。如图
20170317120911452.png

一个View 是如何判断自己为最佳处理点击事件的View的

// recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event; 方法A

// default returns YES if point is in bounds
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;  方法B

对view进行重写这两个方法后,就会发现,点击屏幕后,首先响应的是方法A
如果方法A中,我们没有调用父类的这个方法,那就根据这个方法A的返回view,作为响应事件的View。返回nil ,就是这个View 不响应

如果方法A中 调用了父类的这个方法:[super hitTest:point withEvent:event]; 那这个时候系统就要调用方法B,通过这个方法的返回值,来判断当前这个view能不能响应消息。
如果方法B放回的是No, 那就不用再去遍历它的子视图。方法A 返回的view就是可以响应事件的view。
如果方法B返回的是 YES,那就是遍历它的子视图。(就是上图我们描述的那样,找到合适的view返回,如果找不到,那就由方法A返回的view去响应这个事件。)

//返回一个view来响应事件 (我们如果不想影响系统的事件传递链,在这个方法内,最好调用父类的这个方法)

- (nullableUIView *)hitTest:(CGPoint)point withEvent:(nullableUIEvent *)event

//返回的值可以用来判断是否继续遍历子视图(返回的根据是触摸的point是否在view的frame范围内)
- (BOOL)pointInside:(CGPoint)point withEvent:(nullableUIEvent *)event;
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容