将垂直的两指滑动手势添加到UIScrollView [英] Add vertical two finger swipe gesture to UIScrollView
问题描述
根据如何要为iPhone屏幕上的所有屏幕添加垂直滑动手势,我向 window
中添加了两根手指向下滑动手势,在整个应用中的正常页面上都可以正常工作.但是它在具有 UIScrollView
的页面上失败(如UITableViewController).当我用两根手指在 UIScrollView
上向下滑动时,它会像往常一样滚动.如果我从 UIScrollView
上方的 UINavigationBar
滑动,它再次可以正常工作.
理想的结果是我可以正常地用一根手指滚动tableview,并通过用两根手指滑动页面而不滚动tableview来调用某种方法.这在TweetBot中用于切换暗模式,效果很好.
根据Apple的文档:使用响应者和响应者链来处理事件>,我想我了解了响应程序链的工作原理,所以我想让 UIScrollView
忽略两个手指的滑动手势,以便它可以将此事件传递给 UIWindow
.但我不知道如何:
我尝试从Apple的 还有 关于与joern解决方案不同的一些解释: 而且不必对任何特定的VC做任何事情. 这样,两指滑动手势在普通VC和滚动VC上都可以正常工作. 将 然后,在包含 现在,两指向下的手势在 更新 由于滑动是一个离散手势,因此上述解决方案可能不是完美的解决方案.当您用一根手指缓慢向下滚动时,您会注意到 更好的解决方案可能是使用 可以这样实现: 在您的AppDelegate中: 在您的ViewController中: 您必须从 使用此解决方案, According to How to add a vertical swipe gesture to iPhone app for all screens, I add a two finger swipe down gesture to 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 I tried to implement Any solutions or advice is welcomed. I simplified joern's solution and here is. In And Some explanations about differences from joern's solution: 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 Then, in the Now the two finger down gesture works over a UPDATE Because 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 A better solution might be to use a That could be achieved like this: In your AppDelegate: In your ViewController: You have to take the With this solution the normal scrolling behavior of the 这篇关于将垂直的两指滑动手势添加到UIScrollView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
扩展名AppDelegate:UIGestureRecognizerDelegate {funcgestureRecognizer(_gestureRecognizer:UIGestureRecognizer,应该与其他GestureRecognizer同时识别:UIGestureRecognizer)->布尔{返回真}}
recognizer.state == .change
. recognizer.translation(in:)
的参数应为 window
,这样我就无法对特定的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: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)->布尔{返回真}}
func enableTwoFingerSlideDown(){警卫让appDelegate = UIApplication.shared.delegate为?AppDelegate,让twoFingerGestureRecognizer = appDelegate.twoFingerPanRecognizer别的 {返回}tableView.addGestureRecognizer(twoFingerGestureRecognizer)}
AppDelegate
中获取 UIPanGestureRecognizer
,并将其添加到 UITableView
中.否则,这将无法工作.只需记住在取消此 UIViewController
之前将其添加回 UIWindow
. UITableView
的正常滚动行为保持不变.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.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:UIGestureRecognizerDelegate
's func gestureRecognizer(_:, shouldRequireFailureOf otherGestureRecognizer:)
from Apple's document, or override gestureRecognizerShouldBegin(_)
by inherit UITableView
. But all didn't work.Update - Final Solution
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
}
}
}
extension AppDelegate: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
recognizer.state == .change
is concerned.recognizer.translation(in:)
's parameter should be window
so that I can do nothing about particular VCs.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")
}
}
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)
}
UITableView
.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.UIPanGestureRecognizer
to recognize a two finger pan and then disable the scrolling on the UITableView
while the user is panning using two fingers.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
}
}
func enableTwoFingerSlideDown() {
guard
let appDelegate = UIApplication.shared.delegate as? AppDelegate,
let twoFingerGestureRecognizer = appDelegate.twoFingerPanRecognizer
else {
return
}
tableView.addGestureRecognizer(twoFingerGestureRecognizer)
}
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.UITableView
remains unchanged.