根据如何为iPhone应用程序添加垂直滑动手势,我在
window
中添加了一个双指向下滑动手势,在整个应用程序的普通页面上都可以正常工作。但是在具有UIScrollView
(如UITableViewController)的页面上失败了。当我在UIScrollView
上用两个手指向下滑动时,它只会像正常情况下一样滚动。如果我从位于UIScrollView
上方的UINavigationBar
向下滑动,则再次正常工作。
理想情况是,我可以通过一个手指正常地滚动tableview,并通过用两个手指滑动页面而不滚动tableview来调用某些方法。这在TweetBot中用于切换暗模式,非常完美。
根据苹果文档:使用响应器和响应者链处理事件,我认为我理解了响应者链的工作原理,所以我想要请求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 上都可以正常工作。