根据如何为所有屏幕添加垂直滑动手势到iPhone应用程序的说法,我给window添加了一个双指向下滑动的手势,这在整个应用程序的普通页面上运行得很好。但是它在有UIScrollView的页面上失败了(比如UITableViewController)。当我用两根手指在上滑动时,它只是像往常一样滚动。如果我从UINavigationBar上滑过UIScrollView,它又能正常工作了。
理想的结果是,我可以正常滚动一个手指的表视图,并调用一些方法,用两个手指滑动页面,而不滚动表视图。这是用于TweetBot切换暗模式,工作完美。
根据苹果公司的文件:使用Responders和Responder链处理事件,我想我理解应答器链是如何工作的,所以我想让UIScrollView忽略这两个手指的滑动手势,这样它就可以把这个事件传递给UIWindow。但我想不出如何:
我试着从苹果的UIGestureRecognizerDelegate的文档中实现func gestureRecognizer(_:, shouldRequireFailureOf otherGestureRecognizer:),或者通过继承UITableView来覆盖gestureRecognizerShouldBegin(_),但都没有成功。
欢迎任何解决方案或建议。
更新-最终解决方案
我简化了joern的解决方案,下面是。
在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
}
}关于与joern解决方案不同之处的一些解释:
recognizer.state == .change。recognizer.translation(in:)的参数应该是window,这样我就不能对特定的VC做任何事情。没有必要对任何特定的VC做任何事情。
这样,双指滑动手势在普通VC和滚动VC上都能很好地工作.
发布于 2018-10-24 14:28:20
将UISwipeGestureRecognizer添加到窗口时,保留对它的引用,以便以后可以通过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")
}
}然后,在包含UITableView (或UIScrollView)的UITableView中,您必须在UITableView的pan手势识别器上调用require(toFail:):
func enableTwoFingerSlideDown() {
guard
let appDelegate = UIApplication.shared.delegate as? AppDelegate,
let twoFingerGestureRecognizer = appDelegate.twoFingerSwipeDownRecognizer
else {
return
}
tableView.panGestureRecognizer.require(toFail: twoFingerGestureRecognizer)
}现在,两根手指向下的手势在UITableView上起作用。
更新
因为滑动是一个离散的手势,上面的解决方案可能不是完美的解决方案。当您用一个手指慢慢向下滚动时,您会注意到UITableView不会立即向下滚动。由于UITableView's UIPanGestureDelagate必须等待(两个手指) SwipeDelegate失败,所以延迟时间很短。这需要一些时间。
更好的解决方案可能是使用UIPanGestureRecognizer识别两个手指盘,然后在用户使用两个手指进行摇摄时禁用UITableView上的滚动。
这是可以做到的:
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)
}您必须从UIPanGestureRecognizer中获取AppDelegate并将其添加到UITableView中。否则这就行不通了。请记住,在此UIWindow被取消之前,请将其添加回UIViewController。
使用此解决方案,UITableView的正常滚动行为保持不变。
https://stackoverflow.com/questions/52908002
复制相似问题