以官方文檔的圖舉例: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
複製代碼