본문 바로가기
iOS/App Frameworks

팬제스처와 네비게이션 팝(뒤로가기) 제스처가 상충되는 문제 해결하기

by 탄이. 2020. 7. 4.

문제

현재 회사에서 개발중인 앱에는 가로 스크롤이 가능한 스크롤뷰(콜렉션뷰 포함)들이 각 화면에 다양하게 존재하고 있습니다.

문제는 기기의 왼쪽 엣지를 오른쪽으로 쓸어넘겨서 뒤로가기(interactivePopGesture)를 하고 싶어도 할 수가 없고 스크롤뷰의 가로방향 팬제스처만 인식한다는 겁니다.

특히 화면 전체를 가로 스크롤 가능한 콜렉션뷰가 덮고 있는 화면들이 좀 있는데요.

이 경우에는 특히나 사용성이 떨어집니다. 반드시 좌상단에 있는 뒤로가기 버튼을 탭해줘야만 네비게이션의 이전 스택으로 팝을 할 수 있기 때문이죠.

해결

방법은 간단합니다. UIGestureRecognizerDelegate의 메소드 중 두 제스처인식기가 인식되었을 때 그 중 하나의 인식을 실패하게 할 지를 결정하는 메소드 gestureRecognizer(_: shouldBeRequiredToFailBy:)를 오버라이드 하여 원하는 때에 팬 제스처를 실패하게 해주면 됩니다.

UIGestureRecognizerDelegate를 채택하는 UINavigationController의 서브클래스를 만듭니다.

import UIKit

typealias UINavigationController = PopGestureableNavigationController

class PopGestureableNavigationController: UIKit.UINavigationController {

    override init(rootViewController: UIViewController) {
        super.init(rootViewController: rootViewController)

        setNavigationBarHidden(true, animated: false)
        interactivePopGestureRecognizer?.delegate = self
    }

    required init?(coder aDecoder: NSCoder) {
        return nil
    }
}

extension PopGestureableNavigationController: UIGestureRecognizerDelegate {

    func gestureRecognizer(
                _ gestureRecognizer: UIGestureRecognizer, 
                shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer
        ) -> Bool {
        return viewControllers.count > 1 ? true : false
    }
}

이제 앱 전체의 모든 UINavigationController를 PopGestureableNavigationController로 바꿔주면 되는데요. 꾀나 번거로울것 같군요. 그래서 저는 하지 않았습니다. 그대신 스코프(Scope) 우선순위를 해킹하는 방법으로 다음 코드 한 줄만 작성했습니다.

typealias UINavigationController = PopGestureableNavigationController

자세한 내용은 전수열님의 글을 참고했습니다.

iOS 13 에서 변경된 UIModalPresentationStyle 해킹하기

 

iOS 13 에서 변경된 UIModalPresentationStyle 해킹하기

스코프 우선순위를 해킹해서 iOS 13의 UIModalPresentationStyle 기본값 변경에 대응한 경험을 공유합니다.

medium.com

 

댓글