1. UIView和CALayer
- CALayer负责显示内容contents
- UIView为CALayer提供现实的内容,以及负责处理触摸事件,参与响应链
UIView和CALayer的这种设计模式,体现了六大设计原则中的——单一职能原则。即一个类只负责一件事情。
2. 事件传递与传递链
问:点击View C2,系统是如何找到响应的视图View C2,事件是如何传递的?
2.1 事件传递用到的两个主要的方法
方法1:返回的是UIView,如果某个视图能响应事件,就返回这个视图
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
方法2:返回的是BOOL值,判断某一个点击的位置(CGPoint),是否在当前视图内,如果是,返回YES
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
2.2 传递链,点击屏幕寻找第一响应者的流程
2.3 hitTest内部实现
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
- 检查该视图是否被隐藏,是否可交互,透明值是否大于0.01,如果有一项满足,则返回 nil
- 利用方法
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
检查点击的点是否在当前视图内部,如果不在,则返回 nil - 倒序遍历自己的子视图(后加入的子视图先遍历),每个子视图都调用一次
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
,如果某个子视图返回了一个UIView,则可以return这个view -
如果所有子视图都返回nil,则把自己返回
3. 响应链
事件虽然通过传递链从上到下找到了第一响应者,但是第一响应者不一定能处理这个事件,事件最后由谁来处理,还需要通过一个从下往上的响应链来寻找
- 响应链的流程如上图所示,从UIView → UIView的父视图 → UIViewController → UIWindow → UIApplication → UIApplicationDelegate
3.1 几个方法
- (void)touchesBegin:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
3.2 事件的传递
- 如上图所示,如果点击圆圈地方,C2不能处理,则会交给B2(C2的父视图)处理,如果B2也不能处理,则传递给A(B2的父视图)处理,如果A也不能处理,则会沿着A → UIViewController → UIWindow → UIApplication → UIApplicationDelegate一直向上传递
- 如果当UIApplicationDelegate都不处理这个事件,则这个事件会被丢弃,什么事都不会发生