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
|
|||
|
|
}
|
|||
|
|
}
|