概述
Director是一个用Swift编写的轻量级协调库。
注意:该库为Swift 5.1和iOS 13构建。要运行示例项目,您必须针对iOS 13,这需要Xcode 11测试版。
安装
CocoaPods
pod 'Director', '~> 1.0.0'
Swift包管理器
即将推出
协调器
协调器有助于巩固和管理视图显示状态。它们用于定义应用程序路径的块,同时将导航逻辑与应用程序及视图逻辑分开。协调器仅管理它们所关注的导航。多个协调器可以存在于单个导航堆栈中,每个协调器管理堆栈视图的一部分。同样,协调器可以与所需数量(或多或少)的视图相关联。
导演
导演是一个轻量级协调器实现,有助于使应用程序的导航路径简单且可复用。该库由三个主要组件组成
场景导演
场景协调器
视图协调器
场景导演
SceneDirector
是一个场景级类,它管理场景的窗口和初始视图协调器展示。根据您的目标iOS版本,它将在应用程序启动时或场景连接时初始化和启动。
AppDelegate (iOS 12)
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
private var director: SceneDirector?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
self.director = SceneDirector(
ExampleSceneCoordinator(),
window: self.window!
).start()
return true
}
}
SceneDelegate (iOS 13)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
private var director: SceneDirector!
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else { return }
self.window = UIWindow(windowScene: windowScene)
self.director = SceneDirector(
ExampleSceneCoordinator(),
window: self.window!
).start()
}
}
注意:您可能已经注意到我们上面示例中手动初始化了我们的窗口。因为我们的SceneDirector
管理我们的窗口和初始视图展示,所以我们不使用主Storyboard。您可以直接从项目中删除默认添加的Storyboard文件,并在目标设置中清除“主界面”字段。如果需要,您可以继续为其他视图元素使用Storyboard。只需从您的视图协调器子类直接加载它们即可。
场景协调器
SceneCoordinator
是一个根级协调器类,它管理应用程序显示的初始视图协调器。这应该被继承以在应用程序启动时或场景连接时返回相应的ViewCoordinator
实例。
class ExampleSceneCoordinator: SceneCoordinator {
override func build() -> ViewCoordinator {
return HomeCoordinator()
}
}
视图协调器
视图协调器是一个类,它管理一组相关视图的显示状态、导航路径、展示/消失逻辑。
class HomeCoordinator: ViewCoordinator {
override func build() -> UIViewController {
let vc = HomeViewController()
vc.delegate = self
return vc
}
}
我们希望将导航逻辑从视图中抽象出去。相反,当我们视图中用户触发操作时,我们让协调器来决定如何导航。为了进一步加强这种关注点的分离,我们的视图不应该知道其父协调器。这是一个很重要的点。注意这一点。例如,如果我们想要一个通用的视图在多个不同的协调器中使用怎么办?协议/代理方法允许我们将用户操作传递给协调器,同时保持其足够通用以供重用。
extension HomeCoordinator: HomeViewControllerDelegate {
func homeViewControllerDidTapDetail(_ viewController: HomeViewController) {
push(DetailViewController())
}
func homeViewControllerDidTapHelp(_ viewController: HomeViewController) {
modal(HelpViewController())
}
}
子协调器
很多时候,当我们从应用程序的不同地方呈现相同的视图时,我们的导航路径可能既复杂又繁琐。我们不是简单地推送或以模态方式呈现我们的视图,而是可以将无关的或与其他协调器当前路径明显不同的导航路径分组。
例如,如果我们上面的HomeCoordinator
需要显示拥有自身导航路径的配置文件视图,我们可以将它分组到一个ProfileCoordinator
中,并以HomeCoordinator
的子级启动它。
extension HomeCoordinator: HomeViewControllerDelegate {
...
func homeViewControllerDidTapProfile(_ viewController: HomeViewController) {
start(child: ProfileCoordinator())
}
}
注意:子协调器的呈现方式取决于视图协调器的build()
函数返回的内容。如果返回一个UIViewController
实例,父协调器将开始并推送到其现有的导航堆栈中。然而,如果返回一个UINavigationController
实例,父协调器将这个协调器视为自我管理,并以模态方式呈现。
嵌入式协调器
在某些情况下,视图协调器可能需要手动管理子视图及其呈现。标签栏界面是一个很好的例子。我们的根视图(标签栏)包含多个子视图(它的标签),每个都有自己的导航路径。要实现这一点,可以使用嵌入式视图协调器。
class TabCoordinator: ViewCoordinator {
private var tabBarController: UITabBarController!
private var redCoordinator = RedCoordinator()
private var greenCoordinator = GreenCoordinator()
private var blueCoordinator = BlueCoordinator()
override func build() -> UIViewController {
self.tabBarController = UITabBarController()
self.tabBarController.viewControllers = buildChildren()
return self.tabBarController
}
private func buildChildren() -> [UIViewController] {
startEmbedded(children: [
self.redCoordinator,
self.greenCoordinator,
self.blueCoordinator
])
return [
self.redCoordinator.rootViewController,
self.greenCoordinator.rootViewController,
self.blueCoordinator.rootViewController
]
}
}
通过调用startEmbedded(child:)
或startEmbedded(children:)
,子视图协调器将设置的没有任何自动呈现逻辑。这非常适合构建自定义的多视图界面。
SwiftUI
Director完全支持SwiftUI。在构建视图协调器时,只需返回一个UIHostingController
即可。
class SwiftUICoordinator: ViewCoordinator {
override func build() -> UIViewController {
return UIHostingController(rootView: MyView())
}
}
贡献
欢迎贡献代码。是bug修复还是新功能?提交一个pull request,我们会合并到代码库中!