【问题标题】:Only root-level navigation destinations are effective for a navigation stack with a homogeneous path只有根级导航目的地对具有同构路径的导航堆栈有效
【发布时间】:2022-12-04 18:12:40
【问题描述】:

我正在尝试将 NavigationStack 集成到我的 SwiftUI 应用程序中,我有四个视图 CealUIAppOnBoardingViewUserTypeViewRegisterView。当用户按下OnBoardingView中的按钮时,我想从OnBoardingView导航到UserTypeView,当用户按下UserTypeView 中的按钮时,我想从UserTypeView导航到RegisterView

下面是我的 CealUIApp 代码

@main
struct CealUIApp: App {
    
    @State private var path = [String]()
    
    var body: some Scene {
        WindowGroup {
            NavigationStack(path: $path){
                OnBoardingView(path: $path)
            }
        }
    }
}

OnBoardingView

Button {
                    path.append("UserTypeView")
                } label: {
                    Text("Hello")
                }.navigationDestination(for: String.self) { string in
                    UserTypeView(path: $path)
                }

UserTypeView

Button {
                path.append("RegisterView")
            } label: {
                Text("Hello")
            }.navigationDestination(for: String.self) { string in
                RegisterView()
            }

当按下UserTypeView中的按钮时,我不断导航到UserTypeView而不是RegisterViewXcode中的消息显示Only root-level navigation destinations are effective for a navigation stack with a homogeneous path.

【问题讨论】:

    标签: ios swift swiftui


    【解决方案1】:

    您可以通过将路径类型更改为 NavigationPath 来删除 Only root-level navigation destinations are effective for a navigation stack with a homogeneous path

    @State private var path: NavigationPath = .init()
    

    但是随后您收到一条消息/错误,我认为它可以更好地解释问题A navigationDestination for “Swift.String” was declared earlier on the stack. Only the destination declared closest to the root view of the stack will be used.

    Apple 决定扫描所有可用的视图效率非常低,因此他们将优先使用 navigationDestination

    试想一下,如果您的OnBoardingView也有"RegisterView"的选项

     .navigationDestination(for: String.self) { string in
            switch string{
            case "UserTypeView":
                UserTypeView(path: $path)
            case "RegisterView":
                Text("fakie register view")
            default:
                Text("No view has been set for (string)")
            }
            
        }
    

    SwiftUI 将如何选择合适的?

    那么如何“修”呢?您可以尝试这种替代方法。

    import SwiftUI
    
    @available(iOS 16.0, *)
    struct CealUIApp: View {
        @State private var path: NavigationPath = .init()
        var body: some View {
            NavigationStack(path: $path){
                OnBoardingView(path: $path)
                    .navigationDestination(for: ViewOptions.self) { option in
                        option.view($path)
                    }
            }
        }
        //Create an `enum` so you can define your options
        enum ViewOptions{
            case userTypeView
            case register
            //Assign each case with a `View`
            @ViewBuilder func view(_ path: Binding<NavigationPath>) -> some View{
                switch self{
                case .userTypeView:
                    UserTypeView(path: path)
                case .register:
                    RegisterView()
                }
            }
        }
    }
    @available(iOS 16.0, *)
    struct OnBoardingView: View {
        @Binding var path: NavigationPath
        var body: some View {
            Button {
                //Append to the path the enum value
                path.append(CealUIApp.ViewOptions.userTypeView)
            } label: {
                Text("Hello")
            }
            
        }
    }
    @available(iOS 16.0, *)
    struct UserTypeView: View {
        @Binding var path: NavigationPath
        var body: some View {
            Button {
                //Append to the path the enum value
                path.append(CealUIApp.ViewOptions.register)
            } label: {
                Text("Hello")
            }
            
        }
    }
    @available(iOS 16.0, *)
    struct RegisterView: View {
        var body: some View {
            Text("Register")
            
        }
    }
    @available(iOS 16.0, *)
    struct CealUIApp_Previews: PreviewProvider {
        static var previews: some View {
            CealUIApp()
        }
    }
    

    【讨论】:

      【解决方案2】:

      按照@lorem ipsum 示例,我认为您可以使用@ObservableObject 更改此状态变量 @State private var path: NavigationPath = .init(),这样您就不需要在所有视图上传递@Bindings。您只需将它从 CealUIApp 视图作为 WnvironmentObject 传递下来

      
      class NavigationStack: ObservableObject {
          @Published var paths: NavigationPath = .init()
      }
      
      
      @main
      struct CealUIApp: App {
          
          let navstack = NavigationStack()
          
          var body: some Scene {
              WindowGroup {
                      AppEntry()
                          .environmentObject(navstack)
              }
          }
      }
      
      extension CealUIApp {
          enum ScreenDestinations {
              case userTypeView
              case registerView
              
              
              //Assign each case with a `View`
              @ViewBuilder func view(_ path: Binding<NavigationPath>) -> some View {
                  switch self{
                      case .permissions:
                          UserTypeView()
                      case .seedPhrase:
                          RegisterView()
                  }
              }
          }
      
      }
      
      
      // An extra view after the AppView
      
      struct AppEntry: View {
          
          @EnvironmentObject var navStack: NavigationStack
          
          var body: some View {
              NavigationStack(path: $navStack.paths) {
                  OnBoardingView()
                      .navigationDestination(for: CealUIApp.ScreenDestinations.self) {
                          $0.view($navStack.paths)
                      }
              }
          }
      }
      
      

      然后其余的与@lorem ipsum 所说的相同。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-09
        相关资源
        最近更新 更多