一、UIView和CALayer
UIView继承自UIResponder是系统中最基础的界面元素,所有特定功能的原生组件的基类。UIView负责为CALayer(Core Animation Layer)提供内容,事件处理,参与响应者链,而CALayer继承自NSObject就是用来负责展示内容,所以UIView更像是一个CALayer的管理器,接收frame,bounds等等属性,并赋值到layer上进行渲染。
断点view的初始化过程如下:
1、[LAyer init] 创建layer渲染层
2、[UIView _createLayerWithFrame:] 设置layer的frame
3、[UIView initWithFrame:] 调用view的
重写layer类的setFrame或者setBounds、setCenter方法,能直接修改视觉显示位置,
同是设置view和layer的背景颜色,最终渲染的是layer层的颜色,修改layer层的position即改变了渲染的位置,并且事件能够响应,进一步确认一个事实,view只是一个类似于管理的角色,所有的frame、bounds、center都是赋值给其管理的layer的,那同样的label的text及button的title也是渲染到相应到layer上面。
TLView *view = [[TLView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
- (void)setPosition:(CGPoint)position{ position.x = 200; position.y = 100; [super setPosition:position]; }
二、事件
UIKit框架是用UIResponder作为响应对象,来响应系统传递过来的事件并处理。
1、-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event;
2、-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event;
主要是上述两个方法来处理事件相应并找到最佳响应者,查找方式如下,
主运行循环捕捉到事件--->UIApplication--->UIWidow----->UIView
UIView会调用1方法,而这个方法又会调用2方法,如果2方法返回true及此事件是在当前view内部发生的,则会接着以同样的方式往下遍历此view的子视图,直到找到最佳响应者及点击范围在当前视图内且不在其子视图内,处理事件;如果2方法返回false,则停止遍历返回nil,表明事件不是在当前view范围内发生的,将事件向上抛,直到UIApplication,一直没有响应者,则将事件丢弃。
了解了响应者链,对处理视图事件响应问题就游刃有余了,比如有需求需要子视图不完全在父视图范围内,如点击超出父视图范围的部分,正常情况下不会响应,那如果我们重写hitTest:withEvent:就可以响应事件,达到我们的目的。