NavigationKit 是一个库,它扩展了 SwiftUI 对 NavigationStack (仅限 iOS 16 及以上版本) 的实现,并添加了更多资源来管理用户界面。
本仓库通过 SPM 分发,可以通过两种方式使用
在 Xcode 14 中,前往 File > Packages > Add Package Dependency...,然后粘贴 https://github.com/brennobemoura/navigation-kit.git
// swift-tools-version: 5.7
import PackageDescription
let package = Package(
name: "MyPackage",
products: [
.library(
name: "MyPackage",
targets: ["MyPackage"]
)
],
dependencies: [
.package(url: "https://github.com/brennobemoura/navigation-kit.git", from: "1.0.0")
],
targets: [
.target(
name: "MyPackage",
dependencies: ["NavigationKit"]
)
]
)
可用的主要功能如下所列。对于每个功能,都有一个问题解决方案,开发该方案的目的是为了解决耦合的 SwiftUI 视图问题。
struct ContentView: View {
var body: some View {
NKNavigationStack {
FirstView()
}
}
}
使用 NKNavigationStack 将 NavigationPath 替换为 NavigationAction,这使得开发者能够更好地操作当前堆叠的视图。
struct FirstView: View {
@Environment(\.navigationAction) var navigationAction
var body: some View {
Button("Push") {
// SomeModel needs to be mapped using
// navigationDestination(for:destination:)
// using SwiftUI's method.
navigationAction.append(SomeModel())
}
}
}
struct FirstView: View {
@Environment(\.viewResolver) var viewResolver
var body: some View {
// SomeModel needs to be mapped using
// viewResolver(for:_:) {}.
viewResolver(SomeModel())
}
}
为了将模型与相应的视图进行映射,可以使用 viewResolver(for:_:) 方法,需要在使用前在一个视图中指定。
struct ContentView: View {
var body: some View {
NKNavigationStack {
FirstView()
.viewResolver(for: SomeModel.self) {
SecondView($0)
}
}
}
}
struct FirstView: View {
@Environment(\.sceneAction) var sceneAction
var body: some View {
Button("Push") {
// SomeModel needs to be mapped using
// sceneAction(for:perform:) and
// the sceneActionEnabled() called in the root
// hierarchy.
sceneAction(SomeModel())
}
}
}
为了映射 action,需要调用 sceneAction(for:perform:) 方法,该方法将捕获在任何可能监听的地方抛出的 action。
sceneActionEnabled() 方法后,SceneAction 环境才可用。
struct ContentView: View {
var body: some View {
NKNavigationStack {
FirstView()
}
.sceneAction(for: SomeModel.self) {
print("Action received: \($0)")
}
// but, sceneActionEnabled is needed before
// somewhere in the application
.sceneActionEnabled()
}
}
建议:在 App 的 body 属性中调用 sceneActionEnabled()。
ViewModelConnection 使得可以将 ViewModel 连接到 View,同时保持 SwiftUI State 同步和更新。
此实现旨在在 Coordinator 结构体内部使用。
struct SecondCoordinator: View {
let model: SomeModel
var body: some View {
ViewModelConnection(model, SecondViewModel.init) { viewModel in
SecondView(viewModel: viewModel)
}
}
}
为了按照 Coordinator 的设计意图管理流程,您需要为 ViewModel 指定 destination 属性,以便您可以像这样工作
struct SecondCoordinator: View {
let model: SomeModel
var body: some View {
ViewModelConnection(model, SecondViewModel.init) { viewModel in
SecondView(viewModel: viewModel)
.onReceive(viewModel.$destination) { destination in
switch destination {
case .error(let error):
errorScene(error)
case .third(let third):
thirdScene(third)
case .none:
break
}
}
}
}
}
在 errorScene 或 thirdScene 内部,您可以调用 navigationAction 或 sceneAction 来执行某些操作。