iOS侧滑返回和UIScrollView手势冲突如何解决

最近在开发中遇到这样一个问题,有一个UICollectionView采用水平方向滑动方式,当往右滑动时,常常与侧滑返回的手势出现冲突,致使原本想滑到左边,结果给直接Pop到上一个页面了,本篇就是寻找解决这个问题的方法。bash

实验一app

首先想到了就是采用手势冲突的常规方法,代码以下:ide

if let gesture = self.navigationController?.interactivePopGestureRecognizer {
    gesture.require(toFail: self.collectionView.panGestureRecognizer)
}
复制代码

实验结果代表,这个方法的效果等因而禁用了侧滑返回的手势,由于水平方向UIScrollView的panGestureRecognizer不会失败,可能有人立马想到bounces属性,添加上self.collectionView.bounces = false这一句试试效果,结果证实,此方法仍是行不通。工具

实验二ui

上面简单的方法不行,那就要从拦截手势事件着手了,能够从UIScollView的panGesture或者侧滑手势两个方向尝试,我我的比较倾向于从侧滑手势方向,因此接下来就记录下这个方向的实验过程。spa

在WXViewController中设置代理,代码以下:代理

self.navigationController?.interactivePopGestureRecognizer?.delegate = self
if let gesture = self.navigationController?.interactivePopGestureRecognizer {
    self.collectionView.panGestureRecognizer.require(toFail: gesture)
}
复制代码

实现UIGestureDelegate协议调试

extension WXViewController: UIGestureRecognizerDelegate {
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if self.collectionView.contentOffset.x <= 0 {
            return true
        }
        return false
    }
}
复制代码

实验证实,上面的方法是可行的,可是带来了一个反作用,就是其余页面的侧滑手势失效了,显然是因为侧滑的手势被WXViewController拦截了,其余页面的侧滑手势的delegate为nil,致使系统不能响应了。 解决的办法是,要保存 interactivePopGestureRecognizer?.delegate的代理,而后在适当的地方再还原,在上面的代码中添加以下代码:code

popGestrueDelegate = self.navigationController?.interactivePopGestureRecognizer?.delegate
self.navigationController?.interactivePopGestureRecognizer?.delegate = self
......

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
 self.navigationController?.interactivePopGestureRecognizer?.delegate = popGestrueDelegate
}
复制代码

实验结果代表,上面的方法解决了侧滑和水平方向滑动的手势冲突问题,可是看看代码感受还不是特别完美,若是其余页面也须要解决这个手势冲突呢,那就须要把这些代码copy过去了,因而继续试验。cdn

试验三

既然interactivePopGestureRecognizer是定义在UINavigationController中,那咱们也能够自定义一个UINavigationController,而后拦截这个手势了,代码以下

/*自定义拦截手势协议*/
protocol WXInteractiveGestureDelegate: NSObjectProtocol  {
    func wxGestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
}
/*WXNavigationController*/
override func viewDidLoad() {
    super.viewDidLoad()
    self.interactivePopGestureRecognizer?.delegate = self
}

extension WXNavigationController: UIGestureRecognizerDelegate {
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if let topController = self.topViewController as? WXInteractiveGestureDelegate {
            return topController.wxGestureRecognizerShouldBegin(gestureRecognizer)
        }
        return true
    }
}
复制代码

而后在须要拦截侧滑手势的UIViewController中实现该协议,

extension WXViewController: WXInteractiveGestureDelegate {
    func wxGestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if self.collectionView.contentOffset.x <= 0 {
            return true
        }
        return false
    }
}
复制代码

经过上面方法,实验发现并无解决问题,是哪里的问题呢,打断点调试发现,代理方法是有调用,也是返回true的,可是最后接受手势的确实UIScrollView的panGestrue,因此仍是须要添加如下逻辑

if let gesture = self.navigationController?.interactivePopGestureRecognizer {
    self.collectionView.panGestureRecognizer.require(toFail: gesture)
}
复制代码

添加以后看看效果,嗯,效果还不错。

侧滑手势.gif

后记

开始时说过还能够从UIScrollView的手势着手,有兴趣的同窗能够去尝试一下,若是有其余的更好方法,也欢迎留言讨论。

如需转载,请告知做者并注明做者和来源,谢谢!

注:

一、gif制做工具,PicGIF

相关文章
相关标签/搜索