Skip to content

Instantly share code, notes, and snippets.

@rqbctg
Created August 27, 2025 06:41
Show Gist options
  • Save rqbctg/b5e86599034b092585f09ced6294f321 to your computer and use it in GitHub Desktop.
Save rqbctg/b5e86599034b092585f09ced6294f321 to your computer and use it in GitHub Desktop.
A Simple Yet Powerful RootNavigation Handler
// MARK: - Protocol for Root Changing
protocol RootChanging {
func changeRoot(to viewController: UIViewController, in navigationController: UINavigationController)
}
// MARK: - Concrete Root Changer
class AppRootChanger: RootChanging {
func changeRoot(to viewController: UIViewController, in navigationController: UINavigationController) {
let direction: CATransitionSubtype = .fromRight
let duration = 0.3
let transition = CATransition()
transition.type = CATransitionType.push
transition.subtype = direction
transition.duration = duration
transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
navigationController.view.layer.add(transition, forKey: kCATransition)
navigationController.setViewControllers([viewController], animated: false)
}
}
// MARK: - AppRootNavigationController
class AppRootNavigationController: UINavigationController {
private var cancellables = Set<AnyCancellable>()
var isDarkContent: Bool = true {
didSet { setNeedsStatusBarAppearanceUpdate() }
}
static let changeAppRoot = PassthroughSubject<UIViewController, Never>()
private let rootChanger: RootChanging
init(rootChanger: RootChanging = AppRootChanger()) {
self.rootChanger = rootChanger
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
self.rootChanger = AppRootChanger()
super.init(coder: aDecoder)
}
override var preferredStatusBarStyle: UIStatusBarStyle {
isDarkContent ? .darkContent : .lightContent
}
override func viewDidLoad() {
super.viewDidLoad()
Self.changeAppRoot
.receive(on: DispatchQueue.main)
.sink { [weak self] viewController in
guard let self = self else { return }
self.rootChanger.changeRoot(to: viewController, in: self)
}
.store(in: &cancellables)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setNavigationBarHidden(true, animated: animated)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment