[英]How to implement a global gesture recognizer which detects tap up event?
我嘗試實現一個全局手勢識別器,它能夠全局檢測點擊事件。
以下是我的第一次嘗試。
import UIKit
extension UIWindow {
static var key: UIWindow! {
if #available(iOS 13, *) {
return UIApplication.shared.windows.first { $0.isKeyWindow }
} else {
return UIApplication.shared.keyWindow
}
}
}
class ViewController: UIViewController {
// Lazy is required as self is not ready yet without lazy.
private lazy var globalGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(globalTapped))
private func installGlobalGestureRecognizer() {
UIWindow.key.removeGestureRecognizer(globalGestureRecognizer)
UIWindow.key.addGestureRecognizer(globalGestureRecognizer)
}
@objc func globalTapped() {
print("global tapped!")
}
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func handleTapForRedView(_ gesture: UITapGestureRecognizer) {
print("red view tap")
}
@IBAction func yellowButtonTap(_ sender: Any) {
print("yellow button tap")
}
@IBAction func installGlobalGestureButtonTap(_ sender: Any) {
print("install global gesture")
installGlobalGestureRecognizer()
}
}
然而,這樣的解決方案並不完美。 當點擊區域落在按鈕等其他可觸摸組件上時, globalGestureRecognizer
無法捕獲該事件。 請參考以下視頻。
正如您在視頻中看到的,當觸摸區域為黃色按鈕或紅色自定義視圖時,“全局點擊!” 不會被打印。
我再試一次。
import UIKit
extension UIWindow {
static var key: UIWindow! {
if #available(iOS 13, *) {
return UIApplication.shared.windows.first { $0.isKeyWindow }
} else {
return UIApplication.shared.keyWindow
}
}
}
extension ViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
print("global tapped down!")
return false
}
}
class ViewController: UIViewController {
// Lazy is required as self is not ready yet without lazy.
private lazy var globalGestureRecognizer = UITapGestureRecognizer(target: self, action: nil)
private func installGlobalGestureRecognizer() {
UIWindow.key.removeGestureRecognizer(globalGestureRecognizer)
UIWindow.key.addGestureRecognizer(globalGestureRecognizer)
globalGestureRecognizer.delegate = self
}
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func handleTapForRedView(_ gesture: UITapGestureRecognizer) {
print("red view tap")
}
@IBAction func yellowButtonTap(_ sender: Any) {
print("yellow button tap")
}
@IBAction func installGlobalGestureButtonTap(_ sender: Any) {
print("install global gesture")
installGlobalGestureRecognizer()
}
}
正如您在視頻中看到的,當點擊區域落在按鈕等其他可觸摸組件上時, globalGestureRecognizer
能夠捕獲該事件。
但是,這僅限於點擊事件。 我希望能夠捕獲點擊事件。
有誰知道該怎么做? 我的期望是
幾年前我們做了一些事情來檢測 iOS 上的狀態欄觸摸。 在 App Delegate 中,我們重寫了一個函數,如下所示:
extension AppDelegate {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
// do something here
}
}
在該函數中,我們檢查了觸摸事件並將其位置與窗口的前 50 個像素進行了比較。
這是一個解決方案。
基本上,手指在屏幕上的實例由 UITouch 表示。 多點觸控序列從第一根手指落在屏幕上時開始,並在屏幕上沒有更多手指時結束。 一個 UITouch 對象本質上代表整個多點觸控序列中的同一根手指。 系統將所有這些 UITouch 對象打包在一個稱為 UIEvent 的信封中。 這被發送到我們的 UIWindow,后者使用命中測試和其他東西將其發送到正確的視圖。 這是在其 sendEvent(:) 方法中完成的。
如果我們繼承 UIWindow,我們可以重寫 sendEvent(:) 來攔截事件。 我們所要做的就是查看該事件中的觸摸並確定是否已經結束,然后調用 super,它會正常發送事件。
class MyWindow: UIWindow {
var touchUpDetectionEnabled = true
override func sendEvent(_ event: UIEvent) {
super.sendEvent(event)
guard touchUpDetectionEnabled else { return }
let touchUps = event.allTouches!.filter { $0.phase == .ended }
for each in touchUps {
print("😃")
}
}
}
每次觸摸發生時,該代碼都會打印“😃”,即使您正在滾動 UITableView 等,即使在單個多點觸摸序列中甚至同時發生多次觸摸。
那里有一個布爾值,您可以切換以啟用/禁用全局修飾檢測功能。 哦,還有,確保你的 AppDelegate 創建了我們 UIWindow 子類的一個實例,並為它分配了一個根視圖控制器。
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: MyWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
self.window = MyWindow()
self.window?.rootViewController = ViewController()
self.window?.makeKeyAndVisible()
return true
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.