152 lines
4.8 KiB
Swift
152 lines
4.8 KiB
Swift
//
|
||
// 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
|
||
}
|
||
}
|