2.1 响应链机制

2020-05-13  本文已影响0人  哈库呐玛塔塔__

这里有一个问题,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视图对象

上一篇 下一篇

猜你喜欢

热点阅读