最近在開發中遇到這樣一個問題,有一個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