订购手势识别器

Ordering gesture recognisers

我想知道是否可以就某个问题得到一些澄清,因为我发现 Apple 的文档非常不清楚。我已将边缘平移手势添加到 UIScrollView(或更准确地说是 UIPageViewController 的滚动视图),我发现滚动视图的 swipe/pan 手势与我添加的边缘平移手势冲突。

编辑:按照下面的要求,这是我用来在滚动视图上实现手势的代码和我使用的委托函数。

PageViewController VDL:

override func viewDidLoad(){
    super.viewDidLoad()

    self.dataSource = self

    for eachSubView in self.view.subviews {

        if String(describing: type(of: eachSubView)) ==  "_UIQueuingScrollView" {

            let leftEdge = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(handleSwipeFromLeft(_:)))
            leftEdge.edges = .left
            leftEdge.delegate = self
            eachSubView.addGestureRecognizer(leftEdge)

        }

    }

}

处理从左侧滑动功能:

func handleSwipeFromLeft(_ gesture: UIScreenEdgePanGestureRecognizer) {

    let percent = gesture.translation(in: gesture.view!).x / gesture.view!.bounds.size.width

    if gesture.state == .began {

        interactionController = UIPercentDrivenInteractiveTransition()
        if self.navigationController!.viewControllers.count > 1 {
            self.navigationController?.popViewController(animated: true)
        } else {
            dismiss(animated: true)
        }

    } else if gesture.state == .changed {
        interactionController?.update(percent / 4.8)
    } else if gesture.state == .ended {

        if percent > 0.2 && gesture.state != .cancelled {
            interactionController?.finish()
        } else {
            interactionController?.cancel()
        }

        interactionController = nil
    }
}

GestureRecogniserDelegate:

extension ArticleViewPageController: UIGestureRecognizerDelegate {

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {

        if String(describing: type(of: gestureRecognizer)) == "UIScreenEdgePanGestureRecognizer" {
            return false
        } else {
            return true
        }

    }

}

我一直在阅读 Apple 关于此问题的文档 (Coordinating Multiple Gesture Recognisers, Preferring One Gesture Over Another),但他们的文档没有帮助。在这两份文件的第一份中,有一节内容如下:

To prevent the unintended side effects of the default recognition behavior, you can tell UIKit to recognize gestures in a specific order using a delegate object. UIKit uses the methods of your delegate object to determine whether a gesture recognizer must come before or after other gesture recognizers.

这正是我想要实现的,因为我希望边缘滑动优先于滚动视图的其他手势。但是,该部分继续讨论通过实现我已经实现的 UIGestureRecognizerDelegate 方法 shouldRequireFailureOf 来实现这一点,但是由于滚动视图的平移手势实际上直到手指抬起后才会失败,所以这样做没有什么比边缘手势更喜欢的了。

我还实现了 shouldRecognizeSimultaneouslyWith 方法,它确实解决了冲突,但它也会导致滚动视图在边缘平移期间滚动。

我希望能够按照摘录中所说的那样做,并以特定顺序识别我的手势。非常感谢任何有助于实现这一目标的帮助。

谢谢!

这有点远,但在我看来,您应该将 leftEdge 识别器设置为延迟触摸事件,并使 table 识别器要求 leftEdge 在接管之前失败。

leftEdge.delaysTouchesBegan = true
tableView.panGestureRecognizer.require(toFail: leftEdge)

对于任何试图在未来实现这一非常小众的东西的人,我找到了解决方法。

我像这样实现了 UIGestureRecognizerDelegate 方法 shouldRecognizeSimultaneouslyWith:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {

    return true

} 

因为我只在我的边缘平移手势上实现了委托(如上所示),所以它只在边缘平移被激活时被调用。这停止了​​我的边缘平移和滚动视图的平移之间的冲突,但引入了 PageViewController 分页的问题,而我的边缘平移导致导航堆栈中的弹回。为了解决这个问题,我将以下代码添加到我的边缘手势函数中(同样,如上所述),以便在手势状态为 .begun 时调用:

for eachSubView in self.view.subviews {

    if String(describing: type(of: eachSubView)) ==  "_UIQueuingScrollView", let queueScrollView = eachSubView as? UIScrollView {
        queueScrollView.isScrollEnabled = false
    }

}

最后,我在 PageViewController 的 viewDidAppear 函数中添加了相同的块,只是我设置了 queueScrollView.isScrollEnabled = true。这意味着即使弹出手势被取消,视图之间的分页仍然有效。

这不是一个很好的解决方案,但它确实具有使边缘手势优先于平移手势的预期效果,只是以一种非常不优雅的方式。如果出现更好的答案,我将编辑此 post。