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

时间:2021-01-27 10:08:08

标签: swiftui

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

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

我想要做的是让父视图显示导航视图,然后在该导航视图上推送不同的步骤。

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

df %>%
  filter(city %in% c('bj', 'tj')) %>%
  mutate(direction = 'north')

这很好用。在第一步中,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 对象内实现推送?

我是否应该编写包装视图,在这些视图之上进行导航堆栈处理,并摆脱 switch case?

1 个答案:

答案 0 :(得分:0)

好的,所以如果你想从视图 a 转到 b,你应该不是在你的 NavigationView 中而是在 NavigationView 之后的视图中实现它,这样你就不会破坏动画。为什么?好问题,我真的不知道。如果可能,我将 NavigationView 始终保留在 WindowGroup 下的 App 结构中。

回到正题。基本上,您的步骤和 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()})
        }
    }
}