iOS 13.4 용으로 업데이트 됨
iOS 13.4는 이전 솔루션을 깨뜨 렸으므로 상황이 추악해질 것입니다. iOS 13.4에서이 동작은 이제 private 메서드에 의해 제어되는 것처럼 보입니다 _gestureRecognizer:shouldReceiveEvent:
( shouldReceive
iOS 13.4에 추가 된 새로운 공용 메서드 와 혼동하지 마십시오 ).
대리자를 재정의하거나 nil로 설정하는 다른 게시 된 솔루션이 예기치 않은 동작을 일으킨다는 것을 발견했습니다.
제 경우에는 탐색 스택의 맨 위에 있었고 제스처를 사용하여 하나를 더 팝하려고하면 실패 할 것입니다 (예상대로). 내비게이션 바. 이는 델리게이트가 내비게이션 바가 숨겨져있을 때 제스처가 인식되는 것을 차단할지 여부와 그 밖의 모든 동작이 삭제되는 것 이상을 처리하는 데 사용되기 때문에 의미가 있습니다.
내 테스트 gestureRecognizer(_:, shouldReceiveTouch:)
에서 탐색 모음이 숨겨져있을 때 제스처가 인식되지 않도록 차단하기 위해 원래 대리자가 구현하는 방법 인 것으로 보입니다 gestureRecognizerShouldBegin(_:)
. gestureRecognizerShouldBegin(_:)
델리게이트 작업 을 구현하는 다른 솔루션은 구현 이 없기 때문에 gestureRecognizer(_:, shouldReceiveTouch:)
모든 터치를받는 기본 동작이 발생 하기 때문 입니다.
@Nathan Perry의 솔루션이 가까워 지지만를 구현하지 않으면 respondsToSelector(_:)
델리게이트에 메시지를 보내는 UIKit 코드가 다른 델리게이트 메서드에 대한 구현이 없다고 믿고 forwardingTargetForSelector(_:)
호출되지 않습니다.
따라서 동작을 수정하려는 특정 시나리오에서`gestureRecognizer (_ :, shouldReceiveTouch :)를 제어하고, 그렇지 않으면 나머지 모든 항목을 델리게이트에 전달합니다.
class AlwaysPoppableNavigationController : UINavigationController {
private var alwaysPoppableDelegate: AlwaysPoppableDelegate!
override func viewDidLoad() {
super.viewDidLoad()
self.alwaysPoppableDelegate = AlwaysPoppableDelegate(navigationController: self, originalDelegate: self.interactivePopGestureRecognizer!.delegate!)
self.interactivePopGestureRecognizer!.delegate = self.alwaysPoppableDelegate
}
}
private class AlwaysPoppableDelegate : NSObject, UIGestureRecognizerDelegate {
weak var navigationController: AlwaysPoppableNavigationController?
weak var originalDelegate: UIGestureRecognizerDelegate?
init(navigationController: AlwaysPoppableNavigationController, originalDelegate: UIGestureRecognizerDelegate) {
self.navigationController = navigationController
self.originalDelegate = originalDelegate
}
@objc func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if let navigationController = navigationController, navigationController.isNavigationBarHidden && navigationController.viewControllers.count > 1 {
return true
}
else if let originalDelegate = originalDelegate {
return originalDelegate.gestureRecognizer!(gestureRecognizer, shouldReceive: touch)
}
else {
return false
}
}
@objc func _gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceiveEvent event: UIEvent) -> Bool {
if let navigationController = navigationController, navigationController.isNavigationBarHidden && navigationController.viewControllers.count > 1 {
return true
}
else if let originalDelegate = originalDelegate {
let selector = #selector(_gestureRecognizer(_:shouldReceiveEvent:))
if originalDelegate.responds(to: selector) {
let result = originalDelegate.perform(selector, with: gestureRecognizer, with: event)
return result != nil
}
}
return false
}
override func responds(to aSelector: Selector) -> Bool {
if #available(iOS 13.4, *) {
return originalDelegate?.responds(to: aSelector) ?? false
}
else {
if aSelector == #selector(gestureRecognizer(_:shouldReceive:)) {
return true
}
else {
return originalDelegate?.responds(to: aSelector) ?? false
}
}
}
override func forwardingTarget(for aSelector: Selector) -> Any? {
if #available(iOS 13.4, *), aSelector == #selector(_gestureRecognizer(_:shouldReceiveEvent:)) {
return nil
}
else {
return self.originalDelegate
}
}
}