,我想我了解了响应程序链的工作原理,所以我想让 UIScrollView 忽略两个手指的滑动手势,以便它可以将此事件传递给 UIWindow .但我不知道如何:我尝试从Apple的文档,或通过继承 UITableView覆盖 gestureRecognizerShouldBegin(_).但是一切都没有用.欢迎任何解决方案或建议.更新-最终解决方案我简化了joern的解决方案,这里是在 AppDelegate 中 //除非您想做进一步的事情,否则不必保留对手势的引用.懒惰的var手势:UIPanGestureRecognizer = {让手势= UIPanGestureRecognizer(目标:自我,行动:#selector(twoFingerDidSwipe(recognizer :)))pose.minimumNumberOfTouches = 2pose.maximumNumberOfTouches = 2返回手势}()func application(_ application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplication.LaunchOptionsKey:Any]?)->布尔{pose.delegate = AppDelegatewindow.addGestureRecognizer(手势)返回真}@objc func twoFingerDidSwipe(识别:UIPanGestureRecognizer){让swipeThreshold:CGFloat = 50如果identifierr.state == .changed {//1切换识别器.translation(在:窗口中).y {//2情况...(-swipeThreshold):打印(向上滑动")identifierr.state = .cancelled//3案例swipeThreshold ...:打印(向下滑动")identifier.state = .cancelled默认:休息}}} 还有 扩展名AppDelegate:UIGestureRecognizerDelegate {funcgestureRecognizer(_gestureRecognizer:UIGestureRecognizer,应该与其他GestureRecognizer同时识别:UIGestureRecognizer)->布尔{返回真}} 关于与joern解决方案不同的一些解释:仅涉及 recognizer.state == .change . recognizer.translation(in:)的参数应为 window ,这样我就无法对特定的VC进行任何操作.此识别器触发某些方法后,应将其取消以防止连续触发它们.而且不必对任何特定的VC做任何事情.这样,两指滑动手势在普通VC和滚动VC上都可以正常工作.解决方案将 UISwipeGestureRecognizer 添加到窗口时,请保留对其的引用,以便以后可以通过进行访问AppDelegate : 类AppDelegate:UIResponder,UIApplicationDelegate {var window:UIWindow?var twoFingerSwipeDownRecognizer:UISwipeGestureRecognizer吗?func application(_ application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplication.LaunchOptionsKey:Any]?)->布尔{让twoFingerSwipeDownRecognizer = UISwipeGestureRecognizer(target:self,action:#selector(didRecognizeTwoFingerSwipeDown))twoFingerSwipeDownRecognizer.numberOfTouchesRequired = 2twoFingerSwipeDownRecognizer.direction = .downwindow?.addGestureRecognizer(twoFingerSwipeDownRecognizer)self.twoFingerSwipeDownRecognizer = twoFingerSwipeDownRecognizer返回真}@objc func didRecognizeTwoFingerSwipeDown(recognizer:UISwipeGestureRecognizer){打印(向下滑动")}} 然后,在包含 UITableView (或 UIScrollView )的 UIViewController 中,您必须调用 require(toFail:)在UITableView的平移手势识别器上: func enableTwoFingerSlideDown(){警卫让appDelegate = UIApplication.shared.delegate为?AppDelegate,让twoFingerGestureRecognizer = appDelegate.twoFingerSwipeDownRecognizer别的 {返回}tableView.panGestureRecognizer.require(toFail:twoFingerGestureRecognizer)} 现在,两指向下的手势在 UITableView 上起作用. 更新 由于滑动是一个离散手势,因此上述解决方案可能不是完美的解决方案.当您用一根手指缓慢向下滚动时,您会注意到 UITableView 不会立即向下滚动.延迟很短,因为 UITableView的 UIPanGestureDelagate 必须等待,直到(两指)SwipeDelegate失败为止.这需要一些时间.更好的解决方案可能是使用 UIPanGestureRecognizer 来识别两指平移,然后在用户使用两根手指平移时禁用 UITableView 上的滚动./p>可以这样实现: 在您的AppDelegate中: 类AppDelegate:UIResponder,UIApplicationDelegate {var window:UIWindow?var twoFingerPanRecognizer:UIPanGestureRecognizer?func application(_ application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplication.LaunchOptionsKey:Any]?)->布尔{让twoFingerSwipeDownRecognizer = UIPanGestureRecognizer(target:self,action:#selector(didRecognizeTwoFingerPan))twoFingerSwipeDownRecognizer.minimumNumberOfTouches = 2twoFingerSwipeDownRecognizer.maximumNumberOfTouches = 2twoFingerPanRecognizer?.delegate =自我window?.addGestureRecognizer(twoFingerSwipeDownRecognizer)self.twoFingerPanRecognizer = twoFingerSwipeDownRecognizer返回真}@objc func didRecognizeTwoFingerPan(recognizer:UIPanGestureRecognizer){让tableView = ogniser.view为?UITableView切换识别器状态{案例.开始:tableView?.isScrollEnabled = false大小写已更改:让swipeThreshold:CGFloat = 50切换识别器.translation(in:nil).y {情况...(-swipeThreshold):打印(向上滑动")identifierr.isEnabled =否案例swipeThreshold ...:打印(向下滑动")identifierr.isEnabled =否默认:休息}.cancelled,.end,.failed,.possible的情况:tableView?.isScrollEnabled = true识别器.isEnabled = true}}}扩展AppDelegate:UIGestureRecognizerDelegate {funcgestureRecognizer(_gestureRecognizer:UIGestureRecognizer,应该与其他GestureRecognizer同时识别:UIGestureRecognizer)->布尔{返回真}} 在您的ViewController中: func enableTwoFingerSlideDown(){警卫让appDelegate = UIApplication.shared.delegate为?AppDelegate,让twoFingerGestureRecognizer = appDelegate.twoFingerPanRecognizer别的 {返回}tableView.addGestureRecognizer(twoFingerGestureRecognizer)} 您必须从 AppDelegate 中获取 UIPanGestureRecognizer ,并将其添加到 UITableView 中.否则,这将无法工作.只需记住在取消此 UIViewController 之前将其添加回 UIWindow .使用此解决方案, UITableView 的正常滚动行为保持不变.According to How to add a vertical swipe gesture to iPhone app for all screens, I add a two finger swipe down gesture to window, which works fine on normal pages throughout the whole app. But it fails on the page has UIScrollView (like UITableViewController). When I swipe down with two fingers on UIScrollView, it just scrolls it as normal. If I swipe from UINavigationBar that above UIScrollView, it works fine again.The ideal result is that I can scroll tableview by one finger normally, and call some method by swiping page with two fingers without scrolling tableview. This is used in TweetBot to switch dark mode, works perfectly.According to Apple's document: Using Responders and the Responder Chain to Handle Events, I think I understand how the Responder Chain works, so I want to ask UIScrollView to ignore the two fingers swipe gesture so that it can pass this event to UIWindow. But I can't figure out how to:I tried to implement UIGestureRecognizerDelegate's func gestureRecognizer(_:, shouldRequireFailureOf otherGestureRecognizer:) from Apple's document, or override gestureRecognizerShouldBegin(_) by inherit UITableView. But all didn't work.Any solutions or advice is welcomed.Update - Final SolutionI simplified joern's solution and here is.In AppDelegate// It's not necessary to keep a reference to gesture unless you want to do something further.lazy var gesture: UIPanGestureRecognizer = { let gesture = UIPanGestureRecognizer(target: self, action: #selector(twoFingerDidSwipe(recognizer:))) gesture.minimumNumberOfTouches = 2 gesture.maximumNumberOfTouches = 2 return gesture}()func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { gesture.delegate = AppDelegate window.addGestureRecognizer(gesture) return true}@objc func twoFingerDidSwipe(recognizer: UIPanGestureRecognizer) { let swipeThreshold: CGFloat = 50 if recognizer.state == .changed { // 1 switch recognizer.translation(in: window).y { // 2 case ...(-swipeThreshold): print("Swipe Up") recognizer.state = .cancelled // 3 case swipeThreshold...: print("Swipe Down") recognizer.state = .cancelled default: break } }}Andextension AppDelegate: UIGestureRecognizerDelegate { func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true }}Some explanations about differences from joern's solution:Only recognizer.state == .change is concerned.recognizer.translation(in:)'s parameter should be window so that I can do nothing about particular VCs.After triggering some methods by this recognizer, it should be cancelled to prevent from triggering them continually.And It's unnecessary to do anything about any particular VC.With this, two-finger swipe gesture works fine on both normal VC and scroll VC. 解决方案 When you add the UISwipeGestureRecognizer to your window, keep a reference to it, so you can access it later via the AppDelegate:class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? var twoFingerSwipeDownRecognizer: UISwipeGestureRecognizer? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let twoFingerSwipeDownRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(didRecognizeTwoFingerSwipeDown)) twoFingerSwipeDownRecognizer.numberOfTouchesRequired = 2 twoFingerSwipeDownRecognizer.direction = .down window?.addGestureRecognizer(twoFingerSwipeDownRecognizer) self.twoFingerSwipeDownRecognizer = twoFingerSwipeDownRecognizer return true } @objc func didRecognizeTwoFingerSwipeDown(recognizer: UISwipeGestureRecognizer) { print("SWIPE DOWN") }}Then, in the UIViewController that contains the UITableView (or UIScrollView) you have to call require(toFail:) on the UITableView's pan gesture recognizer:func enableTwoFingerSlideDown() { guard let appDelegate = UIApplication.shared.delegate as? AppDelegate, let twoFingerGestureRecognizer = appDelegate.twoFingerSwipeDownRecognizer else { return } tableView.panGestureRecognizer.require(toFail: twoFingerGestureRecognizer)}Now the two finger down gesture works over a UITableView.UPDATEBecause a swipe is a discrete gesture the solution above might not be the perfect solution. When you scroll down slowly with one finger you will notice that the UITableView will not scroll down instantly. There is a short delay because the UITableView's UIPanGestureDelagate has to wait until the (Two Finger) SwipeDelegate has failed. And that takes some time.A better solution might be to use a UIPanGestureRecognizer to recognize a two finger pan and then disable the scrolling on the UITableView while the user is panning using two fingers.That could be achieved like this:In your AppDelegate:class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? var twoFingerPanRecognizer: UIPanGestureRecognizer? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let twoFingerSwipeDownRecognizer = UIPanGestureRecognizer(target: self, action: #selector(didRecognizeTwoFingerPan)) twoFingerSwipeDownRecognizer.minimumNumberOfTouches = 2 twoFingerSwipeDownRecognizer.maximumNumberOfTouches = 2 twoFingerPanRecognizer?.delegate = self window?.addGestureRecognizer(twoFingerSwipeDownRecognizer) self.twoFingerPanRecognizer = twoFingerSwipeDownRecognizer return true } @objc func didRecognizeTwoFingerPan(recognizer: UIPanGestureRecognizer) { let tableView = recognizer.view as? UITableView switch recognizer.state { case .began: tableView?.isScrollEnabled = false case .changed: let swipeThreshold: CGFloat = 50 switch recognizer.translation(in: nil).y { case ...(-swipeThreshold): print("Swipe UP") recognizer.isEnabled = false case swipeThreshold...: print("Swipe DOWN") recognizer.isEnabled = false default: break } case .cancelled, .ended, .failed, .possible: tableView?.isScrollEnabled = true recognizer.isEnabled = true } }}extension AppDelegate: UIGestureRecognizerDelegate { func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true }}In your ViewController:func enableTwoFingerSlideDown() { guard let appDelegate = UIApplication.shared.delegate as? AppDelegate, let twoFingerGestureRecognizer = appDelegate.twoFingerPanRecognizer else { return } tableView.addGestureRecognizer(twoFingerGestureRecognizer) }You have to take the UIPanGestureRecognizer from the AppDelegate and add it to the UITableView. Otherwise this won't work. Just remember to add it back to the UIWindow before this UIViewController is dismissed.With this solution the normal scrolling behavior of the UITableView remains unchanged. 这篇关于将垂直的两指滑动手势添加到UIScrollView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!