使用 Combine 路由 SwiftUI 视图
Use Combine to route SwiftUI Views
我正在尝试使用 Combine 来路由 SwiftUI 视图,它有点工作,但有一些不需要的行为,我希望有人可以帮助我。我制作了一个 example project,它只包含两个文件,ViewRouter.swift
和 ViewController.swift
,只包含一个 @IBSegueAction
到 return 一个 UIHostingController
:
class ViewRouter
是包含 @ViewBuilder
属性 的 SwiftUI 视图的 ViewModel
。当SwiftUI
视图调用didFinish()
函数时,step
属性设置为下一个View
.
class ViewRouter: ObservableObject {
enum Step { case test1, test2, test3, test4 }
@Published var step: Step = .test1
@ViewBuilder var nextStepView: some View {
switch step {
case .test1:
Test1(router: self)
case .test2:
Test2(router: self)
case .test3:
Test3(router: self)
case .test4:
Test4(router: self)
}
}
func didFinish() {
switch step {
case .test1:
step = .test2
case .test2:
step = .test3
case .test3:
step = .test4
case .test4:
break
}
}
}
这非常适合 Test1
,当点击 Next
link 时,Test1
视图向左动画显示 Test2
。但是,当在 Test2
中点击 Next
时,Test2
会向左移动以显示 Test3
,但随后它会立即向右移动以显示相同的 [=30] =] 视图。在 Test3
.
中点击 Next
时会发生完全相同的情况
并且点击后退按钮总是在 Test1
视图中结束。
除了Text
中的文字外,所有四个视图都相同:
struct Test1: View {
@ObservedObject var router: ViewRouter
@State var nextView = false
var body: some View {
VStack {
NavigationLink(destination: router.nextStepView, isActive: $nextView) {
EmptyView()
}
Text("Test1")
Button(action: {
nextView = true
router.didFinish()
}, label: {
Text("Next")
})
}
}
}
我对 ViewRouter class 进行了一些小改动以使其正常工作。我得出的结论是所有 SwiftUI 视图都需要它们自己的 ViewRouter 实例。对所有视图使用相同的 ViewRouter 共享实例会导致不良行为。我引入了一个 nextStep
可选 属性 ,当视图调用 didFinish
函数时设置为当前步骤,以确保路由器 returns 正确 nextStepView
如果调用第二次或第三次等等。
我已经为示例 Xcode 项目推送了对 GitHub 存储库的更新。
修改后的 class 现在看起来像这样:
class ViewRouter: ObservableObject {
enum Step { case test1, test2, test3, test4 }
@Published var step: Step
private var nextStep: Step?
@ViewBuilder var nextStepView: some View {
switch step {
case .test1:
Test1(router: self)
case .test2:
Test2(router: ViewRouter(step: .test2))
case .test3:
Test3(router: ViewRouter(step: .test3))
case .test4:
Test4(router: ViewRouter(step: .test4))
}
}
init(step: Step) {
self.step = step
}
func didFinish() {
switch step {
case .test1:
if let next = nextStep {
step = next
} else {
step = .test2
nextStep = .test2
}
case .test2:
if let next = nextStep {
step = next
} else {
step = .test3
nextStep = .test3
}
case .test3:
if let next = nextStep {
step = next
} else {
step = .test4
nextStep = .test4
}
case .test4:
break
}
}
}
我正在尝试使用 Combine 来路由 SwiftUI 视图,它有点工作,但有一些不需要的行为,我希望有人可以帮助我。我制作了一个 example project,它只包含两个文件,ViewRouter.swift
和 ViewController.swift
,只包含一个 @IBSegueAction
到 return 一个 UIHostingController
:
class ViewRouter
是包含 @ViewBuilder
属性 的 SwiftUI 视图的 ViewModel
。当SwiftUI
视图调用didFinish()
函数时,step
属性设置为下一个View
.
class ViewRouter: ObservableObject {
enum Step { case test1, test2, test3, test4 }
@Published var step: Step = .test1
@ViewBuilder var nextStepView: some View {
switch step {
case .test1:
Test1(router: self)
case .test2:
Test2(router: self)
case .test3:
Test3(router: self)
case .test4:
Test4(router: self)
}
}
func didFinish() {
switch step {
case .test1:
step = .test2
case .test2:
step = .test3
case .test3:
step = .test4
case .test4:
break
}
}
}
这非常适合 Test1
,当点击 Next
link 时,Test1
视图向左动画显示 Test2
。但是,当在 Test2
中点击 Next
时,Test2
会向左移动以显示 Test3
,但随后它会立即向右移动以显示相同的 [=30] =] 视图。在 Test3
.
Next
时会发生完全相同的情况
并且点击后退按钮总是在 Test1
视图中结束。
除了Text
中的文字外,所有四个视图都相同:
struct Test1: View {
@ObservedObject var router: ViewRouter
@State var nextView = false
var body: some View {
VStack {
NavigationLink(destination: router.nextStepView, isActive: $nextView) {
EmptyView()
}
Text("Test1")
Button(action: {
nextView = true
router.didFinish()
}, label: {
Text("Next")
})
}
}
}
我对 ViewRouter class 进行了一些小改动以使其正常工作。我得出的结论是所有 SwiftUI 视图都需要它们自己的 ViewRouter 实例。对所有视图使用相同的 ViewRouter 共享实例会导致不良行为。我引入了一个 nextStep
可选 属性 ,当视图调用 didFinish
函数时设置为当前步骤,以确保路由器 returns 正确 nextStepView
如果调用第二次或第三次等等。
我已经为示例 Xcode 项目推送了对 GitHub 存储库的更新。
修改后的 class 现在看起来像这样:
class ViewRouter: ObservableObject {
enum Step { case test1, test2, test3, test4 }
@Published var step: Step
private var nextStep: Step?
@ViewBuilder var nextStepView: some View {
switch step {
case .test1:
Test1(router: self)
case .test2:
Test2(router: ViewRouter(step: .test2))
case .test3:
Test3(router: ViewRouter(step: .test3))
case .test4:
Test4(router: ViewRouter(step: .test4))
}
}
init(step: Step) {
self.step = step
}
func didFinish() {
switch step {
case .test1:
if let next = nextStep {
step = next
} else {
step = .test2
nextStep = .test2
}
case .test2:
if let next = nextStep {
step = next
} else {
step = .test3
nextStep = .test3
}
case .test3:
if let next = nextStep {
step = next
} else {
step = .test4
nextStep = .test4
}
case .test4:
break
}
}
}