前沿
在学习事件传递以及响应之前,我们先来了解一下UIView与Calayer的关系。一个View包含有响应的calayer以及backGround. 而calayer中content只负责内容的显示,而View负责提供给 calayer显示的内容,该内容是以一个位图来显示的,如图中的backing store就是一个位图。它们的这种功能方式,正式与单一职责的原则相符。
一、事件传递
(1)所涉及到的方法:
- 返回响应的View
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; - 点击的位置是否当前范围内,如果是,返回YES,否则 NO
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
(2)事件传递流程:
事件传递流程.png当我们点击到屏幕的某个位置的时候,事件首先会传递给UIApplication,接着,又会传递给UIWindow,UIWindow就会判断hitTest:withEvent:来返回最终的视图,在这个方法的内部实际上会调用pointInside:withEvent:方法,判断点击的位置是否在UIWindow范围内,如果是,它会遍历它的子视图,来查找最终的响应视图。而遍历的方式是以倒序遍历的方式,也就是说,最后添加到window的视图,会最优先遍历到,而在遍历到的每一个UIView 它都会调用hit=[sub hitTest:withEvent:]方法,我们可看作是一个递归调用。而这个hit方法,最终会返回一个最终的响应视图。如果返回的hit!=nil,则这个hit会作为最终的响应视图。如果没有,并且在window的范围内,则会将window看作最终的响应视图。以上就是一个完整的事件传递流程。下面我们来以一个流程图,来看一下hitTest方法的内部实现。
(3)hitTest:withEvent:方法的内部实现
hitTest:withEvent:方法的内部实现了解的该方法的内部实现,我们就可以在该方法中作出自己的想要的业务逻辑处理,比如说,我要更改按钮的点击区域。比如:制作形状是方形、点击区域是圆形的按钮。Demo
(4)事件响应的流程:
事件响应的流程图以button为例,当我们点击了按钮之后,最先交给的它的父视图做处理,如果父视图不做处理,事件就会想向上传递,直到有视图或者controller 作出事件处理。否则,它会一直传递下去(view->controller(如果存在,就会传递给controller,不存在就直接传递给window)->window->application->applicationDelegate)。如果,传递到applicationDelegate仍没有对该事件作出处理,那么该事件就会被丢弃,不做响应。
(5)所涉及到的方法:
- -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- -(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- -(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
网友评论