// // CLNavigationController.swift // Crush // // Created by Leon on 2025/7/12. // import UIKit protocol NavigationControllerDelegate: NSObjectProtocol { func popGestureRecognizerShouldBegin() -> Bool } extension NavigationControllerDelegate { func popGestureRecognizerShouldBegin() -> Bool { return true } } class CLNavigationController: UINavigationController { weak var popDelegate: NavigationControllerDelegate? private(set) var pan: UIPanGestureRecognizer! override func viewDidLoad() { super.viewDidLoad() navigationBar.isHidden = true modalPresentationStyle = .fullScreen addFullScreenPan() } override func pushViewController(_ viewController: UIViewController, animated: Bool) { if viewControllers.count > 0 { if viewController is CLBaseViewController { let vc = viewController as! CLBaseViewController vc.hiddenBackButton(of: false) } viewController.hidesBottomBarWhenPushed = true } // 如果viewController已经在navigationStack中,则不进行push if viewControllers.contains(viewController) { return } super.pushViewController(viewController, animated: animated) } override open var childForStatusBarStyle: UIViewController? { return topViewController } private func addFullScreenPan() { // 1.获取系统的Pop手势 guard let systemGes = interactivePopGestureRecognizer else { return } // 2.获取手势添加到的View中 guard let gesView = systemGes.view else { return } // 3.取出target let targets = systemGes.value(forKey: "_targets") as? [NSObject] guard let targetObjc = targets?.first else { return } guard let target = targetObjc.value(forKey: "target") else { return } // 4.取出action let action = Selector(("handleNavigationTransition:")) // 5. 创建自己的pan手势 pan = UIPanGestureRecognizer() gesView.addGestureRecognizer(pan) pan.addTarget(target, action: action) pan.delegate = self } /// 关闭全屏 保留系统手势 func disabledFullScreenPan() { pan.isEnabled = false interactivePopGestureRecognizer?.delegate = self } /// 开启全屏 func enabledFullScreenPan() { pan.isEnabled = true } /// 关闭全屏 和 系统 func disabledPopGesture() { pan.isEnabled = false interactivePopGestureRecognizer?.isEnabled = false } /// 开启全屏 和 系统 func enabledPopGesture() { pan.isEnabled = true interactivePopGestureRecognizer?.isEnabled = true } } extension CLNavigationController: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if viewControllers.count <= 1 { return false } if value(forKey: "_isTransitioning") as? Bool ?? false { return false } let translation = gestureRecognizer.location(in: gestureRecognizer.view) if translation.x <= 0 { return false } if let popDelegate = popDelegate { return popDelegate.popGestureRecognizerShouldBegin() } return true } } // MARK: - 解决全屏滑动时的手势冲突 extension UIScrollView: @retroactive UIGestureRecognizerDelegate { // 当UIScrollView在水平方向滑动到第一个时,默认是不能全屏滑动返回的,通过下面的方法可实现其滑动返回。 override open func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if panBack(gestureRecognizer: gestureRecognizer) { return false } return true } public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith _: UIGestureRecognizer) -> Bool { if panBack(gestureRecognizer: gestureRecognizer) { return true } return false } func panBack(gestureRecognizer: UIGestureRecognizer) -> Bool { if gestureRecognizer == panGestureRecognizer { let point = panGestureRecognizer.translation(in: self) let state = gestureRecognizer.state // 设置手势滑动的位置距屏幕左边的区域 let locationDistance = UIScreen.main.bounds.size.width if state == UIGestureRecognizer.State.began || state == UIGestureRecognizer.State.possible { let location = gestureRecognizer.location(in: self) if point.x > 0, location.x < locationDistance, contentOffset.x <= 0 { return true } } } return false } }