此仓库包含一个实现了 Coordinator 模式的库。Coordinator 模式是一种在 iOS 应用开发中用于管理应用导航流程的设计模式。该库提供了一组类和协议,可用于在 iOS 应用中实现 Coordinator 模式。它适用于 UIKit 或 SwiftUI 应用。其核心导航是使用 UINavigationController (UIKit) 创建的,旨在充分利用导航堆栈。
要在你的 iOS 项目中使用 Coordinator 模式库,你需要将库文件添加到你的项目并设置一个 Coordinator 对象。以下是基本步骤:
首先,让我们定义我们的路径及其视图。
注意: 如果你想创建一个与 UIKit 兼容的 Coordinator,你必须
import UIKCoordinator
,否则import SUICoordinator
。接下来,我们将编写一个 SwiftUI 的例子。
import SUICoordinator
import SwiftUI
enum OnboardingRoute: NavigationRoute {
case firstStep(viewModel: FirstViewModel)
case secondStep(viewModel: SecondViewModel)
// MARK: NavigationRouter
var transition: NavigationTransitionStyle {
switch self {
case .firstStep:
return .push
case .secondStep:
return .modal
}
}
func view() -> any View {
switch self {
case .firstStep(let vm):
return FirstView()
.environmentObject(vm)
case .secondStep(let vm):
return SecondView(viewModel: vm)
}
}
}
其次,让我们创建我们的第一个 Coordinator。所有 Coordinator 都应该实现 start()
函数,然后启动流程(强制性的)。最后,添加额外的流程。
import SUICoordinator
class OnboardingCoordinator: NavigationCoordinator<OnboardingRoute> {
// MARK: Coordinator
override func start(animated: Bool) {
let vm = FirstViewModel(coordinator: self)
router.startFlow(
route: .firstStep(viewModel: vm),
animated: animated
)
}
// MARK: Helper funcs
func showStep2() {
let vm = SecondViewModel(coordinator: self)
router.navigate(to: .secondStep(viewModel: vm))
}
func showHomeCoordinator() {
let coordinator = HomeCoordinatorSUI(currentPage: .settings)
router.navigate(to: coordinator)
}
}
import SUICoordinator
enum HomeRoute: CaseIterable, TabbarPage {
case marketplace
case settings
// MARK: NavigationRouter
func coordinator() -> Coordinator {
switch self {
case .settings:
return SettingsCoordinator()
case .marketplace:
return MarketplaceCoordinator()
}
}
// MARK: TabbarPageDataSource
public var title: String {
switch self {
case .marketplace:
return "Marketplace"
case .settings:
return "Settings"
}
}
public var icon: Image {
switch self {
case .marketplace:
return Image(systemName: "house")
case .settings:
return Image(systemName: "gearshape")
}
}
public var position: Int {
switch self {
case .marketplace:
return 0
case .settings:
return 1
}
}
}
import UIKCoordinator
import UIKit
class HomeCoordinatorUIKit: TabbarCoordinator<HomeRoute> {
// MARK: Constructor
public init() {
super.init(
pages: [.marketplace, .settings],
currentPage: .marketplace
)
}
}
import SUICoordinator
import SwiftUI
import Combine
class HomeCoordinatorSUI: TabbarCoordinator<HomeRoute> {
// MARK: Properties
var cancelables = Set<AnyCancellable>()
// Custom Tabbar view
public init(currentPage: HomeRoute) {
let viewModel = HomeTabbarViewModel()
let view = HomeTabbarView(viewModel: viewModel)
viewModel.currentPage = currentPage
super.init(
customView: view,
pages: [.marketplace, .settings],
currentPage: currentPage
)
viewModel.$currentPage
.sink { [weak self] page in
self?.currentPage = page
}.store(in: &cancelables)
UITabBar.appearance().isHidden = true
}
// Default Tabbar view
public init(default: Bool ) {
super.init(pages: [.marketplace, .settings])
}
}
import SUICoordinator
class MainCoordinator: NavigationCoordinator<MainRoute> {
// MARK: Constructor
init() {
super.init(parent: nil)
router.startFlow(route: .splash, animated: false)
}
// MARK: Coordinator
override func start(animated: Bool = false) {
let coordinator = OnboardingCoordinator(presentationStyle: .fullScreen)
router.navigate(to: coordinator, animated: animated)
}
}
import SUICoordinator
import SwiftUI
enum MainRoute: NavigationRoute {
case splash
// MARK: NavigationRoute
var transition: NavigationTransitionStyle { .push }
func view() -> any View { SplashScreenView() }
}
import SwiftUI
import SUICoordinator
final class SceneDelegate: NSObject, UIWindowSceneDelegate {
var mainCoordinator: MainCoordinator?
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
setupCoordinator(animated: true)
}
private func setupCoordinator(animated: Bool = false) {
mainCoordinator = .init()
setupWindow(controller: mainCoordinator?.root)
BaseCoordinator.mainCoordinator = mainCoordinator
mainCoordinator?.start(animated: animated)
}
private func setupWindow(controller: UIViewController?) {
window?.rootViewController = controller
window?.makeKeyAndVisible()
}
}
import UIKit
@main
final class AppDelegate: NSObject, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
return true
}
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
let sessionRole = connectingSceneSession.role
let sceneConfig = UISceneConfiguration(name: nil, sessionRole: sessionRole)
sceneConfig.delegateClass = SceneDelegate.self
return sceneConfig
}
}
以下是可以执行的最重要的特性和操作:
Router 负责管理导航堆栈并协调不同视图之间的转换。它将导航细节从视图中抽象出来,使它们能够专注于其特定功能,例如:
名称 | 参数 | 描述 |
---|---|---|
navigate(_) |
|
允许你在 Route 中定义的视图之间导航。演示类型有 Push、Modal、ModalFullScreen 和 Custom。 |
navigate(_) |
|
允许你在 Coordinator 之间导航。它调用 start() 函数。 |
startFlow(_) |
|
清除导航堆栈并运行导航流程。 |
present(_) |
|
以模态方式呈现一个视图。 |
pop(_) |
|
从导航堆栈中弹出顶层视图并更新显示。 |
popToRoot(_) |
|
弹出堆栈上的所有视图,除了根视图,并更新显示。 |
dismiss(_) |
|
关闭视图以模态方式呈现的视图。 |
popToView(_) |
|
弹出视图,直到指定的视图位于导航堆栈的顶部。示例:router.popToView(MyView.self) |
finishFlow(_) |
|
弹出堆栈上的所有视图,包括根视图,关闭所有模态视图,并从 Coordinator 堆栈中移除当前 Coordinator。 |
充当与视图分离的实体,将导航逻辑与演示逻辑分离。这种关注点分离允许视图仅专注于其特定功能,而 Navigation Coordinator 负责应用的整体导航流程。一些功能包括:
名称 | 参数 | 描述 |
---|---|---|
router |
Route 类型的变量,允许执行 Router 操作。 | |
forcePresentation(_) |
|
将当前 Coordinator 放在 Coordinator 堆栈的顶部,使其成为活动和可见的 Coordinator。此功能对于从推送通知、通知中心、非典型流程等启动导航流程非常有用。 |
getTopCoordinator(_) |
|
返回位于 Coordinator 堆栈顶部的 Coordinator。 |
restartApp(_) |
|
清除导航堆栈并运行主 Coordinator 导航流程。 |
充当与视图分离的实体,将导航逻辑与演示逻辑分离。这种关注点分离允许视图仅专注于其特定功能,而 Navigation Coordinator 负责应用的整体导航流程。它负责构建 Tab bar (UITabbarController),其中包含在其 Route 中定义的 Coordinator,一些功能包括:
名称 | 参数 | 描述 |
---|---|---|
currentPage |
返回当前选定的页面。 | |
getCoordinatorSelected() |
|
返回与选定选项卡关联的选定 Coordinator。 |
setPages(_) |
|
更新页面设置。 |
forcePresentation(_) |
|
将当前 Coordinator 放在 Coordinator 堆栈的顶部,使其成为活动和可见的 Coordinator。此功能对于从推送通知、通知中心、非典型流程等启动导航流程非常有用。 |
SPM
打开 Xcode 和你的项目,点击 File / Swift Packages / Add package dependency... 。在文本框 "Enter package repository URL" 中,输入 https://github.com/felilo/ALCoordinator 并按两次 Next。
欢迎对 ALCoordinator 库做出贡献!要贡献,只需 fork 此仓库并在新分支中进行更改。准备好更改后,向此仓库提交 pull request 以供审核。
许可证
ALCoordinator 库是在 MIT 许可证下发布的。有关更多信息,请参见 LICENSE 文件。