|
//
// NavigationController.swift
// PaiaiUIKit
//
// Created by FFIB on 2019/4/23.
// Copyright © 2019 FFIB. All rights reserved.
//
import UIKit
public class NavigationController: UINavigationController {
private var operation: Operation = .none
private var barConfigures: [UIViewController?: NavigationBarConfiguration] = [:]
private var _fromFakeBar = UIToolbar()
private var _toFakeBar = UIToolbar()
override public init(rootViewController: UIViewController) {
super.init(navigationBarClass: NavigationBar.classForCoder(), toolbarClass: nil)
self.viewControllers = [rootViewController]
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
override public func viewDidLoad() {
super.viewDidLoad()
delegate = self
interactivePopGestureRecognizer?.delegate = self
interactivePopGestureRecognizer?.isEnabled = true
}
public override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if operation == .none { return }
navigationBar.getBarBackground()?.alpha = 0
}
}
fileprivate extension NavigationController {
func setFakeNavigationBar() {
UIView.setAnimationsEnabled(false)
guard let to = transitionCoordinator?.viewController(forKey: .to),
let from = transitionCoordinator?.viewController(forKey: .from) else { return }
switch self.operation {
case .push:
barConfigures[to] = NavigationBarConfiguration(navigationBar: navigationBar)
case .pop:
navigationBar.setBackgroundImage(barConfigures[to]?.backgroundImage, for: .default)
default:
break
}
setToFakeNavigationBar(for: to)
setFromFakeNavigationBar(for: from)
navigationBar.apply(for: .transparent)
UIView.setAnimationsEnabled(true)
if barConfigures[to]?.isHidden != barConfigures[from]?.isHidden {
setNavigationBarHidden(barConfigures[to]?.isHidden ?? false, animated: true)
}
}
func setFromFakeNavigationBar(for from: UIViewController) {
if let navBarFrame = from.getFakeBarFrame(for: navigationBar) {
_fromFakeBar = UIToolbar(configure: barConfigures[from] ?? .default)
_fromFakeBar.delegate = self
_fromFakeBar.frame = navBarFrame
from.view.addSubview(_fromFakeBar)
}
}
func setToFakeNavigationBar(for to: UIViewController) {
if let navBarFrame = to.getFakeBarFrame(for: navigationBar) {
_toFakeBar = UIToolbar(configure: barConfigures[to] ?? .default)
_toFakeBar.delegate = self
_toFakeBar.frame = navBarFrame
to.view.addSubview(_toFakeBar)
}
}
func clearFake() {
_fromFakeBar.removeFromSuperview()
_toFakeBar.removeFromSuperview()
guard let from = transitionCoordinator?.viewController(forKey: .from),
operation == .pop else { return }
barConfigures.removeValue(forKey: from)
}
}
extension NavigationController: UINavigationControllerDelegate {
public func navigationController(_ navigationController: UINavigationController,
animationControllerFor operation: UINavigationController.Operation,
from fromVC: UIViewController,
to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
self.operation = operation
return nil
}
public func navigationController(_ navigationController: UINavigationController,
willShow viewController: UIViewController,
animated: Bool) {
if operation == .none {
self.barConfigures[viewController] = NavigationBarConfiguration(navigationBar: navigationBar)
return
}
transitionCoordinator?.animate(alongsideTransition: { context in
if context.isInteractive {
self.operation = .pop
}
self.setFakeNavigationBar()
}, completion: { context in
let vc: UIViewController?
if context.isCancelled {
self.operation = .push
vc = context.viewController(forKey: .from)
} else {
vc = context.viewController(forKey: .to)
}
self.navigationBar.getBarBackground()?.alpha = 1
self.navigationBar.apply(for: self.barConfigures[vc] ?? .default)
self.clearFake()
})
}
}
extension NavigationController: UIGestureRecognizerDelegate {
public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer == interactivePopGestureRecognizer {
return viewControllers.count > 1
}
return true
}
}
extension NavigationController: UIToolbarDelegate {
public func position(for bar: UIBarPositioning) -> UIBarPosition {
return .top
}
}
|