XCoordinator
XCoordinator copied to clipboard
Implementing sliding side menu with XCoordinator
Hi, I really like this framework and would like to use it for navigating with a side menu, however, I'm stuck with its implementation into a container beside a sideMenu controller. Or would be possible to create an animation style for sliding the existing controller and showing the menu? Can you please advise on a possible way how to implement it?
You would need to implement your own container view controller (ie. SlideMenuController) that manages two child view controllers: a bottom (menu) and top (current screen) Your container view controller would need to have some ability to open/close the menu.
Once you have that setup you would need to do the following:
- Create your own SlideMenuCoordinator inherited from BaseCoordinator. Your rootViewController would be your SlideMenuController type.
- Create your own SlideMenuTransition based on Transition<SlideMenuController>, adding open and close options for the transitions types available.
- Use your coordinator like normal!
@DaliborK Hi bro
Recently, I developed the feature you want using REFrostedViewController
and XCoordinator
. so, I want to share with you and the rest of the communities that used this framework.
you have to create one main coordinator and a side menu coordinator.
import XCoordinator
import REFrostedViewController
import RxSwift
enum MainRoute: Route {
case initial
case side
case action(Destination)
}
final class MainCoordinator: BaseCoordinator<MainRoute, Transition<REFrostedViewController>> {
required init(route: RouteType? = .initial, factory: FactoryType) {
self.factory = factory
super.init(rootViewController: REFrostedViewController(), initialRoute: .initial)
prepareRootViewController()
}
override func prepareTransition(for route: RouteType) -> TransitionType {
do {
switch route {
case .initial:
let mainViewController = MainViewController()
rootViewController.contentViewController = mainViewController
mainViewController.sideMenuButton.rx.tap
.bind(with: self) { (this, _) in
this.trigger(.side)
}.disposed(by: disposeBag)
return .none()
case .side:
var sideMenuVC = rootViewController.menuViewController as? SideMenuViewController
if rootViewController.menuViewController == nil {
sideMenuVC = SideMenuViewController()
rootViewController.menuViewController = sideMenuVC
sideMenuVC?.viewModel?.didSelectItem.debounce(.microseconds(200))
.asObservable()
.bind(with: self, onNext: { (this, destination) in
this.rootViewController.hideMenuViewController {
this.trigger(.action(destination))
}
}).disposed(by: disposeBag)
}
rootViewController.presentMenuViewController()
return .none()
case .action(let destination):
let coordinator = SideMenuCoordinator(rootViewController: rootViewController)
return .route(destination.menuRoute(), on: coordinator)
}
}catch let error {
log.error(error, tag: Self.self)
return .none()
}
}
private func prepareRootViewController() {
rootViewController.direction = .left
rootViewController.liveBlur = false
rootViewController.animationDuration = 0.25
rootViewController.liveBlurBackgroundStyle = .dark
rootViewController.blurRadius = 10.0
rootViewController.blurTintColor = .primaryGray
rootViewController.blurSaturationDeltaFactor = 0.5
let width = UIScreen.main.bounds.width * 0.863_111_1
rootViewController.limitMenuViewSize = true
rootViewController.menuViewSize = CGSize(width: width, height: 0)
}
}
the SideMenuCoordinatoor
would be
enum MenuRoute: Route {
case inbox
case unknown
}
final class SideMenuCoordinatoor: BaseCoordinator<MenuRoute, Transition<UIViewController>> {
deinit {
log.verbose("Deinit \(Self.self)", tag: Self.self)
}
override func prepareTransition(for route: MenuRoute) -> TransitionType {
switch (route) {
case .inbox:
let coordinator = InboxCoordinator()
return .presentOnRoot(coordinator, animation: .default)
case .unknown:
return .none()
}
}
}