为啥当点击区域落在按钮上时 UIGestureRecognizerDelegate 的 shouldRecognizeSimultaneouslyWith 没有被执行?
Posted
技术标签:
【中文标题】为啥当点击区域落在按钮上时 UIGestureRecognizerDelegate 的 shouldRecognizeSimultaneouslyWith 没有被执行?【英文标题】:Why UIGestureRecognizerDelegate 's shouldRecognizeSimultaneouslyWith is not executed, when the tap region fall on button?为什么当点击区域落在按钮上时 UIGestureRecognizerDelegate 的 shouldRecognizeSimultaneouslyWith 没有被执行? 【发布时间】:2021-07-30 10:20:16 【问题描述】:我想要
-
检测屏幕任意位置的全局修饰事件
不会影响按钮、自定义视图等组件。下面的按钮,自定义视图仍然能够接收点击事件。
我做的是
-
在
UIApplication.shared.keyWindow
中安装UITapGestureRecognizer
在UIGestureRecognizerDelegate
中,为shouldRecognizeSimultaneouslyWith
返回true
,这样***keyWindow 就不会阻止按钮、自定义视图接收点击事件。
这是我的代码
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,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer)
-> Bool
print(">>> shouldRecognizeSimultaneouslyWith returns true")
return true
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)
globalGestureRecognizer.delegate = self
@objc func globalTapped()
print(">>> global tapped")
override func viewDidLoad()
super.viewDidLoad()
// Do any additional setup after loading the view.
@IBAction func buttonClicked(_ sender: Any)
print("yellow button tap\n")
@IBAction func handleTap(_ gesture: UITapGestureRecognizer)
print("red view tap\n")
@IBAction func installButtonClicked(_ sender: Any)
print("install global gesture")
installGlobalGestureRecognizer()
这是点击红色自定义视图时发生的情况
点击红色自定义视图时(按预期工作)
install global gesture
>>> shouldRecognizeSimultaneouslyWith returns true
>>> shouldRecognizeSimultaneouslyWith returns true
>>> global tapped
red view tap
点击黄色按钮时(全局手势不起作用)
install global gesture
yellow button tap
这就是我为自定义红色视图和黄色按钮安装点击事件处理程序的方式。
有谁知道,为什么在点击按钮时不调用shouldRecognizeSimultaneouslyWith
?我希望在点击黄色按钮时
shouldRecognizeSimultaneouslyWith
执行并返回 true
黄色按钮点击事件处理程序已执行
已执行全局手势点击事件处理程序
谢谢。
【问题讨论】:
部分问题是UIControl
上的.touchUpInside
不是Tap 手势。您可能需要另一种方法。这是一篇可能值得一读的(较旧的)文章:dzone.com/articles/… ...您可能想通过Combine查看接收和处理事件
我在your previous question 中发布了一个适用于所有情况的全局修饰的简单解决方案。它不符合您的要求吗?还是你没看到
【参考方案1】:
正如@DonMag 正确所说,发生这种情况是因为UIGestureRecognizer
s 没有处理按钮触摸
UIControl
直接从UIWindow
获得接触,而它又从UIApplication
获得接触。您可以将其中任何一个子类化以处理触摸。
-
要使用
UIWindow
子类,您需要在SceneDelegate
中创建其实例,然后手动重新初始化情节提要,如下所示:
class CustomWindow: UIWindow
override func sendEvent(_ event: UIEvent)
super.sendEvent(event)
print(#function, event)
class SceneDelegate: UIResponder, UIWindowSceneDelegate
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
guard let scene = (scene as? UIWindowScene) else return
window = CustomWindow(windowScene: scene)
window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
-
我更喜欢使用
UIApplication
子类。它需要更多的更改,但不需要重新初始化逻辑。另外,如果你在 iPad 上使用了很多场景,你也不需要考虑它:
class CustomUIApplication: UIApplication
override func sendEvent(_ event: UIEvent)
super.sendEvent(event)
print(#function, event)
从AppDelegate
中删除@main
注释
创建main.swift
,内容如下:
UIApplicationMain(
CommandLine.argc,
CommandLine.unsafeArgv,
NSStringFromClass(CustomUIApplication.self),
NSStringFromClass(AppDelegate.self)
)
【讨论】:
【参考方案2】:将 UIView 作为背景视图,然后将 UIButton 作为背景视图层上方的不同层(重要:应确认 UIButton 未放置在新的背景视图内)并将手势识别器提供给背景视图.
【讨论】:
【参考方案3】:原因是在viewDidLoad()
期间,您的ViewController
的某些属性尚未定义,并且还没有准备好呈现另一个ViewController
。
为了更好地理解enter link description here
【讨论】:
以上是关于为啥当点击区域落在按钮上时 UIGestureRecognizerDelegate 的 shouldRecognizeSimultaneouslyWith 没有被执行?的主要内容,如果未能解决你的问题,请参考以下文章