説明なし

NavigationController.swift 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. //
  2. // NavigationController.swift
  3. // PaiaiUIKit
  4. //
  5. // Created by FFIB on 2019/4/23.
  6. // Copyright © 2019 FFIB. All rights reserved.
  7. //
  8. import UIKit
  9. public class NavigationController: UINavigationController {
  10. private var operation: Operation = .none
  11. private var barConfigures: [UIViewController?: NavigationBarConfiguration] = [:]
  12. private var _fromFakeBar = UIToolbar()
  13. private var _toFakeBar = UIToolbar()
  14. override public init(rootViewController: UIViewController) {
  15. super.init(navigationBarClass: NavigationBar.classForCoder(), toolbarClass: nil)
  16. self.viewControllers = [rootViewController]
  17. }
  18. required init?(coder aDecoder: NSCoder) {
  19. super.init(coder: aDecoder)
  20. }
  21. override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
  22. super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
  23. }
  24. override public func viewDidLoad() {
  25. super.viewDidLoad()
  26. delegate = self
  27. interactivePopGestureRecognizer?.delegate = self
  28. interactivePopGestureRecognizer?.isEnabled = true
  29. }
  30. public override func viewDidLayoutSubviews() {
  31. super.viewDidLayoutSubviews()
  32. if operation == .none { return }
  33. navigationBar.getBarBackground()?.alpha = 0
  34. }
  35. }
  36. fileprivate extension NavigationController {
  37. func setFakeNavigationBar() {
  38. UIView.setAnimationsEnabled(false)
  39. guard let to = transitionCoordinator?.viewController(forKey: .to),
  40. let from = transitionCoordinator?.viewController(forKey: .from) else { return }
  41. switch self.operation {
  42. case .push:
  43. barConfigures[to] = NavigationBarConfiguration(navigationBar: navigationBar)
  44. case .pop:
  45. navigationBar.setBackgroundImage(barConfigures[to]?.backgroundImage, for: .default)
  46. default:
  47. break
  48. }
  49. setToFakeNavigationBar(for: to)
  50. setFromFakeNavigationBar(for: from)
  51. navigationBar.apply(for: .transparent)
  52. UIView.setAnimationsEnabled(true)
  53. if barConfigures[to]?.isHidden != barConfigures[from]?.isHidden {
  54. setNavigationBarHidden(barConfigures[to]?.isHidden ?? false, animated: true)
  55. }
  56. }
  57. func setFromFakeNavigationBar(for from: UIViewController) {
  58. if let navBarFrame = from.getFakeBarFrame(for: navigationBar) {
  59. _fromFakeBar = UIToolbar(configure: barConfigures[from] ?? .default)
  60. _fromFakeBar.delegate = self
  61. _fromFakeBar.frame = navBarFrame
  62. from.view.addSubview(_fromFakeBar)
  63. }
  64. }
  65. func setToFakeNavigationBar(for to: UIViewController) {
  66. if let navBarFrame = to.getFakeBarFrame(for: navigationBar) {
  67. _toFakeBar = UIToolbar(configure: barConfigures[to] ?? .default)
  68. _toFakeBar.delegate = self
  69. _toFakeBar.frame = navBarFrame
  70. to.view.addSubview(_toFakeBar)
  71. }
  72. }
  73. func clearFake() {
  74. _fromFakeBar.removeFromSuperview()
  75. _toFakeBar.removeFromSuperview()
  76. guard let from = transitionCoordinator?.viewController(forKey: .from),
  77. operation == .pop else { return }
  78. barConfigures.removeValue(forKey: from)
  79. }
  80. }
  81. extension NavigationController: UINavigationControllerDelegate {
  82. public func navigationController(_ navigationController: UINavigationController,
  83. animationControllerFor operation: UINavigationController.Operation,
  84. from fromVC: UIViewController,
  85. to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
  86. self.operation = operation
  87. return nil
  88. }
  89. public func navigationController(_ navigationController: UINavigationController,
  90. willShow viewController: UIViewController,
  91. animated: Bool) {
  92. if operation == .none {
  93. self.barConfigures[viewController] = NavigationBarConfiguration(navigationBar: navigationBar)
  94. return
  95. }
  96. transitionCoordinator?.animate(alongsideTransition: { context in
  97. if context.isInteractive {
  98. self.operation = .pop
  99. }
  100. self.setFakeNavigationBar()
  101. }, completion: { context in
  102. let vc: UIViewController?
  103. if context.isCancelled {
  104. self.operation = .push
  105. vc = context.viewController(forKey: .from)
  106. } else {
  107. vc = context.viewController(forKey: .to)
  108. }
  109. self.navigationBar.getBarBackground()?.alpha = 1
  110. self.navigationBar.apply(for: self.barConfigures[vc] ?? .default)
  111. self.clearFake()
  112. })
  113. }
  114. }
  115. extension NavigationController: UIGestureRecognizerDelegate {
  116. public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
  117. if gestureRecognizer == interactivePopGestureRecognizer {
  118. return viewControllers.count > 1
  119. }
  120. return true
  121. }
  122. }
  123. extension NavigationController: UIToolbarDelegate {
  124. public func position(for bar: UIBarPositioning) -> UIBarPosition {
  125. return .top
  126. }
  127. }