简体   繁体   English

如何实现检测点击事件的全局手势识别器?

[英]How to implement a global gesture recognizer which detects tap up event?

I try to implement a global gesture recognizer, which able to detect tap up event, globally.我尝试实现一个全局手势识别器,它能够全局检测点击事件。

The following is my 1st attempt.以下是我的第一次尝试。

1st attempt : Global tap up gesture recognizer.第一次尝试:全局点按手势识别器。 (Not perfect) (不完美)

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()
    }
}

However, such solution is not perfect.然而,这样的解决方案并不完美。 When the tap up region falls on other touchable components like button, globalGestureRecognizer is NOT able to capture the event.当点击区域落在按钮等其他可触摸组件上时, globalGestureRecognizer无法捕获该事件。 Please refer to the following video.请参考以下视频。

As you can see in the video, when the touch up region is yellow button, or red custom view, "global tapped!"正如您在视频中看到的,当触摸区域为黄色按钮或红色自定义视图时,“全局点击!” will NOT be printed.不会被打印。

在此处输入图片说明


I try another attempt.我再试一次。

2nd attempt: Only able to detect tap down (Not perfect)第二次尝试:只能检测到点击(不完美)

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()
    }
}

As you can see in the video, when the tap region fall on other touchable components like button, globalGestureRecognizer is able to capture the event.正如您在视频中看到的,当点击区域落在按钮等其他可触摸组件上时, globalGestureRecognizer能够捕获该事件。

在此处输入图片说明

But, this only limit to tap down event.但是,这仅限于点击事件。 What I wish is to able to capture the tap up event.我希望能够捕获点击事件。

Does anyone has idea how to do so?有谁知道该怎么做? My expectation are我的期望是

  1. Global gesture will NOT block the original event for button, custom views...全局手势不会阻止按钮、自定义视图的原始事件...
  2. Global gesture will able to detect touch up event anywhere.全局手势将能够在任何地方检测触摸事件。 Even if the event falls on button, custom views... Global gesture still able to detect them.即使事件落在按钮上,自定义视图......全局手势仍然能够检测到它们。

We did something a few years ago to detect the status bar touches on iOS.几年前我们做了一些事情来检测 iOS 上的状态栏触摸。 In App Delegate we overrode a function like so :在 App Delegate 中,我们重写了一个函数,如下所示:


extension AppDelegate {

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        // do something here
    }
}

In that function we inspected the touch event and compared its location to the the top 50 pixels of the window.在该函数中,我们检查了触摸事件并将其位置与窗口的前 50 个像素进行了比较。

Here's a solution.这是一个解决方案。

Basically, an instance of a finger on the screen is represented by a UITouch.基本上,手指在屏幕上的实例由 UITouch 表示。 A multitouch sequence begins when the first finger comes down on the screen, and ends when there are no more fingers on the screen.多点触控序列从第一根手指落在屏幕上时开始,并在屏幕上没有更多手指时结束。 One UITouch object essentially represents the same finger throughout the multitouch sequence.一个 UITouch 对象本质上代表整个多点触控序列中的同一根手指。 The system packages all these UITouch objects in an envelope called a UIEvent.系统将所有这些 UITouch 对象打包在一个称为 UIEvent 的信封中。 This is sent to our UIWindow, who sends it to the correct view using hit testing and stuff.这被发送到我们的 UIWindow,后者使用命中测试和其他东西将其发送到正确的视图。 This is done in its sendEvent(:) method.这是在其 sendEvent(:) 方法中完成的。

If we subclass UIWindow, we can override sendEvent(:) to intercept the event.如果我们继承 UIWindow,我们可以重写 sendEvent(:) 来拦截事件。 All we have to do is look at the touches in that event and determine if one has ended, and then call super, which sends the event normally.我们所要做的就是查看该事件中的触摸并确定是否已经结束,然后调用 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("😃")
        }
    }
}

That code prints a "😃" each time a touch up happens, even if you were scrolling a UITableView etc, and even if multiple touch ups happen in a single multi touch sequence, or even simultaneously.每次触摸发生时,该代码都会打印“😃”,即使您正在滚动 UITableView 等,即使在单个多点触摸序列中甚至同时发生多次触摸。

There's a bool in there that you can toggle to enable/disable the global touch up detection feature.那里有一个布尔值,您可以切换以启用/禁用全局修饰检测功能。 Oh and, make sure your AppDelegate creates an instance of our UIWindow subclass, and assigns it a root view controller.哦,还有,确保你的 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.

相关问题 如何识别调用哪个手势识别器? - how to identify which tap gesture recognizer is called? 如何使用Swift为多个子视图实现点击手势识别器 - How to implement a tap gesture recognizer for multiple subviews with Swift 手势识别器,用于屏幕上特定位置的点击事件 - Gesture recognizer for tap event at specific positions on the screen 点击手势识别器-点击了哪个对象? - tap gesture recognizer - which object was tapped? 如何以编程方式触发UIView的点击手势识别器 - How to trigger tap gesture recognizer of UIView programmatically 点击手势识别器 - Tap Gesture Recognizer In Bounds 使用轻敲手势识别器时未检测到几何元素,但它检测到body-splitcontainers-split123 - Geometry Elements are not being detected when using tap gesture recognizer but it detects body-splitcontainers-split123 传递事件时,在图像上点击手势识别器会引发错误 - Tap gesture recognizer on image throws error when passing event Pan和Tap手势识别器用于相同的视图,需要为另一个视图失败? - Pan and Tap gesture recognizer for same view, which need to fail for the other? 点击手势识别器不适用于UIVcrollView内的UIWebiew,它位于UIView内部 - Tap gesture recognizer Not working for UIWebiew inside UIScrollView,which is inside UIView
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM