在SwiftUI中从父视图推送多个导航链接



我想实现一个向导,用户必须通过多个屏幕才能完成注册过程。

在SwiftUI中,最简单的方法是让每个视图在完成后将下一个视图推送到导航堆栈上,但这会在视图本身中编码视图之间的整个导航,我想避免它。

我想做的是让父视图显示导航视图然后在那个导航视图上推送不同的步骤

我已经有一些工作看起来像这样:

struct AddVehicleView: View {
@ObservedObject var viewModel: AddVehicleViewModel
var body: some View {
NavigationView {
switch viewModel.state {
case .description:
AddDescriptionView(addDescriptionViewModel: AddVehicleDescriptionViewModel(), addVehicleViewModel: viewModel)
case .users:
AddUsersView(viewModel: AddUsersViewModel(viewModel.vehicle), addVehicleViewModel: viewModel)
}
}
}
}

这很好。在第一步中,使用必要的信息更新AddVehicleViewModel,重新评估AddVehicleView,切换案例跳转到下一个选项,并呈现下一个视图以完成向导。

然而,这个问题是没有导航堆栈动画。视图只是被替换。我怎么能改变这个系统,即视图被推,而不实现AddDescriptionView对象内的推?

我应该写包装器视图做导航堆栈处理在这些视图的顶部,并摆脱开关情况?

如果你想从视图a跳转到视图b你不应该在你的NavigationView中实现这个而是在NavigationView之后的视图中实现,这样你就不会破坏动画效果。为什么?好问题,我真的不知道。当可能的时候,我把我的NavigationView总是在WindowGroup下的应用结构中。

回到正题。基本上在你的步骤和NavigationView之间应该有一个中间视图。这个视图(StepperView)将包含步骤的导航逻辑。这样可以保持动画的完整。

import SwiftUI
class AddVehicleViewModel: ObservableObject {

enum StateType {
case description
case users1
case users2
}


@Published var state: StateType? = nil

}
struct AddDescriptionView: View {
@ObservedObject var viewModel: AddVehicleViewModel

@State var text: String = ""
var body: some View {
GeometryReader {proxy in
VStack {
TextField("test", text: self.$text).background(RoundedRectangle(cornerRadius: 10).fill(Color.white).frame(width: 150, height: 40)).padding()
Button("1") {
viewModel.state = .users1
}
}.frame(width: proxy.size.width, height: proxy.size.height, alignment: .center).background(Color.orange)
}
}
}
struct AddUsersView: View {
@ObservedObject var viewModel: AddVehicleViewModel


var body: some View {
GeometryReader {proxy in
ZStack {
Button("2") {
viewModel.state = .users2
}
}.frame(width: proxy.size.width, height: proxy.size.height, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/).background(Color.orange)
}
}
}
struct AddUsersView2: View {
@ObservedObject var viewModel: AddVehicleViewModel


var body: some View {
GeometryReader {proxy in
ZStack {
Button("3") {
viewModel.state = .description
}
}.frame(width: proxy.size.width, height: proxy.size.height, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/).background(Color.orange)
}
}
}
struct StepperView: View {

@ObservedObject var viewModel: AddVehicleViewModel = AddVehicleViewModel()

var body: some View {
VStack {
NavigationLink(
destination: AddDescriptionView(viewModel: viewModel),
isActive: .constant(viewModel.state == .description),
label: {EmptyView()})
if viewModel.state == .users1 {
NavigationLink(
destination: AddUsersView(viewModel: viewModel),
isActive: .constant(true),
label: {EmptyView()})
}
if viewModel.state == .users2 {
NavigationLink(
destination: AddUsersView2(viewModel: viewModel),
isActive: .constant(true),
label: {EmptyView()})
}
}.onAppear {
viewModel.state = .description
}
}
}
class BackBarButtonItem: UIBarButtonItem {
@available(iOS 14.0, *)
override var menu: UIMenu? {
set {
// Don't set the menu here
// super.menu = menu
}
get {
return super.menu
}
}
}
struct AddVehicleView: View {
@ObservedObject var viewModel: AddVehicleViewModel = AddVehicleViewModel()

var body: some View {
NavigationView {
NavigationLink(
destination: StepperView(),
isActive: .constant(true),
label: {EmptyView()})
}
}
}

最新更新