这里有一个问题,CALayer和UIView的区别中有一条叫做CALayer不能直接处理响应事件,不是不能!它也有类似的hitTest的方法,只不过需要手动调用。
说的时候仍然可以说CALayer不响应事件,但是要明白自己的想法,比如:但是不全对,我觉得他只是不能直接处理,手动调用hitTest方法来判断也是可以响应事件的。
CALayer 和 UIView 之间其实就是单一职责设计原则的体现。
一、hitTest的工作原理
当调用到一个视图的hitTest方法的时候。方法内部首先会判断视图不接受触摸事件的三种情况:
不接受用户交互userInteractionEnabled = NO
视图被隐藏hidden = YES
视图的透明度非常小
然后通过调用pointInside方法来判断触摸点是否在自己的范围内,如果不在返回nil。
然后开始判断当前view是否有subViews,如果不存在返回自身。如果存在,则将point 转换为相对于subView的坐标,然后继续调用subView的hittest方法,系统会在subView中的hitTest方法中继续执行上述流程,递归操作,直到找到一个最合适的View作为返回的对象。如果后边的subViews都因为上述三种情况,不能接受触摸事件,或者点击区域不在范围。则最后返回之前相对顶层的self;
注:这里问的是hitest的工作原理,所以我没有提及前边的东西。如果问你事件的分发(传递)机制,那么除了上边的,前边还应加上如下的内容。
发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中,UIApplication会从事件队列中取出最前面的事件,并将事件分发下去,首先会将事件发送给应用程序的keyWindow,找到他的根视图然后就是上边hitTest的逻辑了
二、如何扩大点击button时的热区范围
第一种:重写button的pointInside方法,扩大原来的bounds范围
可以设置个接口来设置想扩大的范围
bounds = CGRectInset(bounds, -0.5 * widthDelta, -0.5 * heightDelta);
return CGRectContainsPoint(bounds, point);
第二种:重写button的hitTest方法,原理和上边一样。
三、如何实现不规则图形的热区
没实现过,但是我想这个图形我应该是会用UIBezierPath来画出来的,这个类里边有个containsPoint方法:用这个方法来判断是否接受触摸事件。
四、responseChain(响应链)是怎么工作的
事件的响应和事件传递的顺序正好相反。
首先由view来尝试处理事件,如果他处理不了,事件将被传递到他的父视图superview。
superview也尝试来处理事件,如果他处理不了,继续传递他的父视图UIViewcontroller.view。
UIViewController.view尝试来处理该事件,如果处理不了,将把该事件传递给UIViewController。
UIViewController尝试处理该事件,如果处理不了,将把该事件传递给主窗口Window。
主窗口Window尝试来处理该事件,如果处理不了,将传递给应用单例Application。
如果Application也处理不了,则该事件将会被丢弃。
五、C视图中包含A,B两个button并且AB是平级的关系,从界面上看A在B的下面,B的面积小于A,但是B视图扩大了热区,并跟A的热区大小一致,A、B的center相同,此时hittest如何工作
首先问 是如何扩大的B视图的热区 反正我通过上述两种情况都是只能点击到B 无法点击到A。
如果是重写hitTest, 那没得说,直接返回的就是B视图对象。
如果是重写pointInside,因为返回yes 并且B视图没有子视图,所以hitTest方法中返回的也是B视图对象
网友评论