[英]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.