以官方文档的图举例:ios
若是 text field 没有处理事件, UIKit 会将事件传递给它的父视图 UIView 对象,依次传递到 UIViewController 的根视图,若还不能处理,则传递给 UIWindow 。若是 window 不能处理事件,则将该事件再传递给 UIApplication。bash
UIKit 使用基于 view 的 hit-testing
去决定 touch 事件发生的位置。在发生 touch 事件后,UIKit 会比较 touch 的位置所在的视图是否在视图层级中。hitTest(_:with:)
会将包含 touch 事件的最上层的视图变为第一响应者。app
若是 touch 的位置超出视图的边界,那 hitTest(_:with:)
方法会忽略该视图的全部子视图。所以,当一个视图的 clipsToBounds 为 false 时,即便 touch 的位置未超出子视图的边界,子视图也不会响应该事件。ide
下面解释一下若是 touch 的位置超出视图的边界,那 hitTest(_:with:) 方法会忽略该视图的全部子视图
:函数
若是咱们有上图层级结构,blueView 是 greenView 的子视图,grayView 是 blueView 的子视图,三个视图都添加 UITapGestureRecognizer 手势,若是你点击 grayView 中超出 blueView 的部分它是不会响应 grayView 的 action,由于该部分已经超出了 blueView 部分,因此 blueView 及其全部子视图都会被响应链忽略。因此,你点击 grayView 中超出 blueView 的部分,响应者是 greenView,会响应 greenView 的 action 。ui
当发生一个 touch 事件时,UIKit 会建立一个 UITouch 的对象,并将它与一个视图联系起来。须要注意的是,当 touch 的位置或者其余参数改变时, UIKit 会将 UITouch 对象的信息更新。可是 UITouch 对象的 view 属性并不会变。即便 UITouch 对象的位置已经超出原始视图的边界,UITouch 对象的 view 属性值也不会改变。当 touch 结束,UIKit 会释放 UITouch 对象。spa
该方法主要用来返回接受 touch 事件的视图层中最上层的且包含当前 point 的子视图。code
它经过 point(inside:with:) 函数来寻找包含 point 的子视图,若是 point(inside:with:) 返回 true,则再往上一直找到最上层且包含 point 的子视图。cdn
你能够经过重写它来对某些子视图隐藏响应事件。当视图的 hidden 为 true 或 isUserInteractionEnabled 为 false 或 alpha 的值小于 0.01 的时候,这些视图将被该方法忽略。对象
你能够经过重写响应者的 next 属性来修改响应链。当你修改以后,下一个响应者即你返回的那个对象。
下面是 UIKit 各种默认下一个响应者:
若是咱们在添加手势的视图上面添加一个带有 action 的 button ,若是咱们点击 button 会触发 视图的手势事件 仍是 button 的 action 呢?
答案是 button 的 action 。看官方文档咱们会看见这么一句话手势处理器不会影响 UIKit controls 处理事件的能力。
不单单是 UIButton ,其余下面的对象也不会受手势识别器的影响:
以上这些皆为 UIControl 的子类。
// 将按钮的点击范围上下左右扩大10pt的范围,注意范围不要超出父视图的边界,超出范围依旧无效。
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
let newFrame = CGRect(x: bounds.origin.x - 10, y: bounds.origin.y - 10, width: bounds.size.width + 20, height: bounds.size.height + 20)
return newFrame.contains(point)
}
复制代码
button.contentEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
复制代码
// 经过修改响应者依赖 来使 scrollView及子类 的手势响应失效
if let rec = navigationController?.interactivePopGestureRecognizer {
collectionView.panGestureRecognizer.require(toFail: rec)
}
复制代码
1.UIWindow 接受到一个事件,执行 hit-test 去寻找应该接受该事件的对象
二、hitTest:withEvent 将会经过调用 pointInside :withEvent: 方法来判断
视图是否包含当前事件的位置。
三、一直递归调用 hitTest:withEvent 直到找到最上层且包含 point 的对象,即为第一响应者。
复制代码
subview -> superview ... -> root view -> view controller -> root view controller -> window -> UIAPPlication - app delegate
复制代码