Swift: 如何使用 Xcoordinator 从子协调器设置根视图控制器?
Swift: How to use Xcoordinator to set a root view controller from child coordinator?
我正在尝试了解如何使用 XCoordinator 从子协调器设置根视图控制器。
我有一个运行应用协调器的应用委托。
我的模式是:
AppDelegate
- App Coordinator
--- Main Menu Coordinator
--- Game Coorinator
(见图)
应用程序协调器不应该直接了解特定的视图控制器,因为我认为视图控制器应该由各自的协调器管理。
因此,应用程序协调器应管理协调器之间的流程并设置根初始协调器。
遗憾的是,屏幕是空白的,并且一直抱怨我做不到 "Pushing a navigation controller is not supported"。
但是如果我直接在我的 appcoordinator 中实例化视图控制器就没问题,我不知道为什么。
// AppCoordinator
enum AppRoute: Route {
case mainmenu
case game
}
class AppCoordinator: NavigationCoordinator<AppRoute> {
init() {
super.init(initialRoute: .mainmenu)
}
// MARK: Overrides
override func prepareTransition(for route: AppRoute) -> NavigationTransition {
let router = MainMenuCoordinator().strongRouter
return .push(router)
}
}
这应该启动 MainMenuCoordinator 的初始视图控制器
enum MainMenuRoute: Route {
case mainmenu
}
// MainMenuCoordinator
class MainMenuCoordinator: NavigationCoordinator<MainMenuRoute> {
init() {
super.init(initialRoute: .mainmenu)
}
override func prepareTransition(for route: MainMenuRoute) -> NavigationTransition {
print ("route: \(route as Any)")
let vc = MainMenuViewController.instantiate(.main)
return .push(vc)
}
}
但是这个 returns 是一个空白屏幕,并且抱怨不支持推送。
但是,如果我移动这段代码:
let vc = MainMenuViewController.instantiate(.main)
return .push(vc)
AppCoordinator
像这样:
// MARK: AppCoordinator Overrides
override func prepareTransition(for route: AppRoute) -> NavigationTransition {
let vc = MainMenuViewController.instantiate(.main)
return .push(vc)
}
还好。出现了一个屏幕——但主菜单协调器不再是 "followed"
我想知道 -- 你如何做到这一点,以便应用程序协调器将责任委托给它的子协调器?
感谢您提供的任何帮助。
谢谢
// 编辑:根据提供的答案,我尝试了另一种尝试,将父协调器的引用传递给子协调器。
我希望 mainmenucoordinator
使用它自己的路线集合;我不想仅仅依赖 AppRoutes
.
中定义的任何路由
所以我的应用程序协调员有这些路线:
enum AppRoute: Route {
case mainmenu
case game
}
class AppCoordinator: NavigationCoordinator<AppRoute> {
init() {
let defaultRoute: AppRoute = .mainmenu
super.init(initialRoute: defaultRoute)
self.rootViewController.view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
}
}
我的主要协调员有这些路线:
enum MainMenuRoute: Route {
case mainmenu
case selectPlayer
case playgame
}
class MainMenuCoordinator: NavigationCoordinator<MainMenuRoute> {
// For my child coordinators, keep a strong reference to parent
private var router: StrongRouter<AppRoute>?
/// ...
}
当我初始化它时,我设置了父级。
// MainMenuCoordinator: Init
convenience init(router: StrongRouter<AppRoute>) {
self.init(initialRoute: .mainmenu)
}
但现在它不会使用我为 MainMenuCoordinator
定义的任何路由;相反,它使用 AppRoute
示例:
正在尝试在 MainMenuCoordinator.prepareTransition
中设置路由器
override func prepareTransition(for route: MainMenuRoute) -> NavigationTransition {
print ("route: \(route as Any)")
switch route {
case .mainmenu:
let vc = MainMenuViewController.instantiate(.main)
vc.router = strongRouter
return .push(vc)
// ....
}
}
主菜单视图控制器引用了:
class MainMenuViewController: UIViewController, Storyboarded {
// MARK: - Stored properties
var router: UnownedRouter<MainMenuRoute>!
}
通过这些编辑,根视图控制器现在是白色的;但记录器仍然抱怨我无法推送视图控制器。
我是这样做的:
class MainCoordinator: NavigationCoordinator<ApplicationRoute> {
convenience init() {
var defaultRoute: ApplicationRoute = .showAuthentification
if ApplicationSettings.shared.isLoggedIn {
defaultRoute = .showApplicationRoot
}
self.init(defaultRoute: defaultRoute)
self.rootViewController.view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
}
override func prepareTransition(for route: ApplicationRoute) -> NavigationTransition {
switch route {
case .showAuthentification:
return .multiple(.dismissToRoot(animation: .fadeInstant),
.presentFullScreen(AuthentificationCoordinator(router: strongRouter),
animation: .fadeInstant))
case .showApplicationRoot:
return .multiple(.dismissToRoot(animation: .fadeInstant),
.presentFullScreen(TabControllerCoordinator(router: strongRouter),
animation: .fadeInstant))
}
}
}
并且在独生子女协调员中:
class AuthentificationCoordinator: NavigationCoordinator<AuthentificationRoute> {
// For my child coordinators I keep a strong reference to the parent, so I can use it later
private var router: StrongRouter<SMCApplicationRoute>?
convenience init(router: StrongRouter<SMCApplicationRoute>) {
self.init(defaultRoute: .initial)
self.router = router
}
override func prepareTransition(for route: AuthentificationRoute) -> NavigationTransition {
switch route {
case .initial:
let initialVC = LandingPageViewController.loadFromXIB(type: LandingPageViewController.self)
initialVC.router = strongRouter
return .push(initialVC, animation: .fade)
case .showLogin:
let loginVC = LoginViewController.loadFromXIB(type: LoginViewController.self)
loginVC.router = strongRouter
return .push(loginVC, animation: .fade)
case .showHome:
// Here I trigger the other route from MainCoordinator. If I log in, the AuthentificationCoordinator will get destroyed, with all the child coordinators with root controllers
return .trigger(SMCApplicationRoute.showApplicationRoot, on: router!)
}
}
}
我认为有更好的解决方案,但我发现这是有效的。如果代码不能自我解释,请告诉我 ;)
我正在尝试了解如何使用 XCoordinator 从子协调器设置根视图控制器。
我有一个运行应用协调器的应用委托。
我的模式是:
AppDelegate - App Coordinator --- Main Menu Coordinator --- Game Coorinator
(见图)
应用程序协调器不应该直接了解特定的视图控制器,因为我认为视图控制器应该由各自的协调器管理。
因此,应用程序协调器应管理协调器之间的流程并设置根初始协调器。
遗憾的是,屏幕是空白的,并且一直抱怨我做不到 "Pushing a navigation controller is not supported"。
但是如果我直接在我的 appcoordinator 中实例化视图控制器就没问题,我不知道为什么。
// AppCoordinator
enum AppRoute: Route {
case mainmenu
case game
}
class AppCoordinator: NavigationCoordinator<AppRoute> {
init() {
super.init(initialRoute: .mainmenu)
}
// MARK: Overrides
override func prepareTransition(for route: AppRoute) -> NavigationTransition {
let router = MainMenuCoordinator().strongRouter
return .push(router)
}
}
这应该启动 MainMenuCoordinator 的初始视图控制器
enum MainMenuRoute: Route {
case mainmenu
}
// MainMenuCoordinator
class MainMenuCoordinator: NavigationCoordinator<MainMenuRoute> {
init() {
super.init(initialRoute: .mainmenu)
}
override func prepareTransition(for route: MainMenuRoute) -> NavigationTransition {
print ("route: \(route as Any)")
let vc = MainMenuViewController.instantiate(.main)
return .push(vc)
}
}
但是这个 returns 是一个空白屏幕,并且抱怨不支持推送。
但是,如果我移动这段代码:
let vc = MainMenuViewController.instantiate(.main)
return .push(vc)
AppCoordinator
像这样:
// MARK: AppCoordinator Overrides
override func prepareTransition(for route: AppRoute) -> NavigationTransition {
let vc = MainMenuViewController.instantiate(.main)
return .push(vc)
}
还好。出现了一个屏幕——但主菜单协调器不再是 "followed"
我想知道 -- 你如何做到这一点,以便应用程序协调器将责任委托给它的子协调器?
感谢您提供的任何帮助。 谢谢
// 编辑:根据提供的答案,我尝试了另一种尝试,将父协调器的引用传递给子协调器。
我希望 mainmenucoordinator
使用它自己的路线集合;我不想仅仅依赖 AppRoutes
.
所以我的应用程序协调员有这些路线:
enum AppRoute: Route {
case mainmenu
case game
}
class AppCoordinator: NavigationCoordinator<AppRoute> {
init() {
let defaultRoute: AppRoute = .mainmenu
super.init(initialRoute: defaultRoute)
self.rootViewController.view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
}
}
我的主要协调员有这些路线:
enum MainMenuRoute: Route {
case mainmenu
case selectPlayer
case playgame
}
class MainMenuCoordinator: NavigationCoordinator<MainMenuRoute> {
// For my child coordinators, keep a strong reference to parent
private var router: StrongRouter<AppRoute>?
/// ...
}
当我初始化它时,我设置了父级。
// MainMenuCoordinator: Init
convenience init(router: StrongRouter<AppRoute>) {
self.init(initialRoute: .mainmenu)
}
但现在它不会使用我为 MainMenuCoordinator
定义的任何路由;相反,它使用 AppRoute
示例:
正在尝试在 MainMenuCoordinator.prepareTransition
override func prepareTransition(for route: MainMenuRoute) -> NavigationTransition {
print ("route: \(route as Any)")
switch route {
case .mainmenu:
let vc = MainMenuViewController.instantiate(.main)
vc.router = strongRouter
return .push(vc)
// ....
}
}
主菜单视图控制器引用了:
class MainMenuViewController: UIViewController, Storyboarded {
// MARK: - Stored properties
var router: UnownedRouter<MainMenuRoute>!
}
通过这些编辑,根视图控制器现在是白色的;但记录器仍然抱怨我无法推送视图控制器。
我是这样做的:
class MainCoordinator: NavigationCoordinator<ApplicationRoute> {
convenience init() {
var defaultRoute: ApplicationRoute = .showAuthentification
if ApplicationSettings.shared.isLoggedIn {
defaultRoute = .showApplicationRoot
}
self.init(defaultRoute: defaultRoute)
self.rootViewController.view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
}
override func prepareTransition(for route: ApplicationRoute) -> NavigationTransition {
switch route {
case .showAuthentification:
return .multiple(.dismissToRoot(animation: .fadeInstant),
.presentFullScreen(AuthentificationCoordinator(router: strongRouter),
animation: .fadeInstant))
case .showApplicationRoot:
return .multiple(.dismissToRoot(animation: .fadeInstant),
.presentFullScreen(TabControllerCoordinator(router: strongRouter),
animation: .fadeInstant))
}
}
}
并且在独生子女协调员中:
class AuthentificationCoordinator: NavigationCoordinator<AuthentificationRoute> {
// For my child coordinators I keep a strong reference to the parent, so I can use it later
private var router: StrongRouter<SMCApplicationRoute>?
convenience init(router: StrongRouter<SMCApplicationRoute>) {
self.init(defaultRoute: .initial)
self.router = router
}
override func prepareTransition(for route: AuthentificationRoute) -> NavigationTransition {
switch route {
case .initial:
let initialVC = LandingPageViewController.loadFromXIB(type: LandingPageViewController.self)
initialVC.router = strongRouter
return .push(initialVC, animation: .fade)
case .showLogin:
let loginVC = LoginViewController.loadFromXIB(type: LoginViewController.self)
loginVC.router = strongRouter
return .push(loginVC, animation: .fade)
case .showHome:
// Here I trigger the other route from MainCoordinator. If I log in, the AuthentificationCoordinator will get destroyed, with all the child coordinators with root controllers
return .trigger(SMCApplicationRoute.showApplicationRoot, on: router!)
}
}
}
我认为有更好的解决方案,但我发现这是有效的。如果代码不能自我解释,请告诉我 ;)