点击一个按钮之后发生了什么?以前基本上没有自己验证过这些东西, 其中有的时候需要拦截事件用的是这样的一段代码:
1 | |
但这是怎么得来的呢?来论证一下。
视图是否能响应
首先userInteractionEnabled = NO和hidden = YES这两种情况是肯定不能响应的, 但是alpha <= 0.01这个我倒没试过, 因为实际的需求中也不可能存在这种透明度的视图, 自己试过才发现确实是这样, alpha必须大于等于0.02的时候才有响应,
视图是否在点击的范围内
也就是[self pointInside:point withEvent:event]这句, 如果返回了YES肯定就是在范围内的(也可能有欺骗肉眼的情况, 后面会说道), 这也毋庸置疑。
事件的传递
1 | |
这两个方法其中第一个大致说的意思是会返回一个在点击的点上面的 视图层次中最远的视图(= = 应该就是最上层的视图被我们点击的), 第二个就简单了大致是说这个视图是否包含我们点击的点。
其探究事件传递的话, 主要会用到第一个方法, 我们可以重写第一个方法看看他执行了多少步:
1 | |
其中打印的class非常多 = =, 如果你使用了系统控件比如UINavigationController或UITabbarController, 他们的部分视图也会在上面, 就不粘贴了, 其传递过程确实是从UIWindow开始, 但UIWindow也未必是顶层, 有可能是UITextEffectsWindow, 一直到我们所点击的view, 所以如果是某个视图重写了这个方法, 倒序遍历也是对的。
所以最初的代码可以解释为:
1 | |
下面来看一下复杂情况下的情况。
平行视图重合情况
我们可以随意切换两个视图的userInteractionEnabled的属性值来观察他们最终的响应情况。
1 | |
层叠视图重合情况
如果有不可交互的视图上添加了可交互的视图, 则点击事件不能正常响应, 事件传递会到不可交互那一层截止。
1 | |
这时我们给UILabel设置userInteractionEnabled = YES响应的情况如何?
1 | |
放大点击热区
有些时候我们会用到一写比较小的按钮, 比如我们上架应用前都会有一个用户协议, 那这个协议是可以勾选和不勾选的, 往往这种勾选框在实际的ui中都会很小, 点击很影响用户体验, 如何做到放大点击热区呢, 用到的就是pointInside: withEvent:这个方法。比如有两个这样的视图:
1 | |
现在_button的响应范围就是他的大小50x50假如我们想把它放大到100x100可以这样做:
1 | |
这样 所有小于100x100的按钮的点击热区全部被放大到了100x100, 即可实现不在按钮范围内点击也可以响应的情况(也就上面说过的欺骗肉眼的情况)
响应过程
可以通过观察一个view的nextResponder属性来看他是怎么被响应的
1 | |
结果也显而易见, 是从最上层开始向下响应, 一直到AppDelegate, 其响应过程大致为(中间去掉了一些不常见的view)ViewController -> UINavigationController -> UITabBarController -> UIWindow -> UIApplication ->AppDelegate