最近在开发中遇到这样一个问题,有一个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)
}
复制代码
添加以后看看效果,嗯,效果还不错。
后记
开始时说过还能够从UIScrollView的手势着手,有兴趣的同窗能够去尝试一下,若是有其余的更好方法,也欢迎留言讨论。
如需转载,请告知做者并注明做者和来源,谢谢!
注:
一、gif制做工具,PicGIF