SwiftUI - List / ForEach 与 NavigationLink 和 isActive 结合使用时无法正常工作

SwiftUI - List / ForEach in combination with NavigationLink and isActive doesn't work properly

我正在尝试在 SwiftUI 的列表或 ForEach 循环中执行 NavigationLink。不幸的是,我遇到了一个非常奇怪的行为(例如,当点击 Leo 时它打开了 Karl,打开 Max 也指向 Karl)。

我已经发现它与 NavigationLink 中的“isActive”属性有关。不幸的是,我需要它来实现这里的行为:https://i.stack.imgur.com/g0BFz.gif which is also asked here SwiftUI - Nested NavigationView: Go back to root.

我也尝试过使用选择和标签属性,但我无法实现“返回根”机制。

示例如下:


import SwiftUI


struct Model: Equatable, Hashable {
    var userId: String
    var firstName: String
    var lastName: String
}


struct ContentView: View {
    
    @State var navigationViewIsActive: Bool = false
    
    var myModelArray: [Model] = [
        Model(userId: "27e880a9-54c5-4da1-afff-05b4584b1d2f", firstName: "Leo", lastName: "Test"),
        Model(userId: "1050412a-cb12-4160-b7e4-2702ab8430c3", firstName: "Max", lastName: "Test"),
        Model(userId: "1050412a-cb12-4160-b7e4-2702ab8430c3", firstName: "Karl", lastName: "Test")]
    
    var body: some View {
        NavigationView {
            List(myModelArray, id: \.self) { model in
                NavigationLink(destination: secondView(firstName: model.firstName), isActive: $navigationViewIsActive){ Text(model.firstName) }
            }
            .listStyle(PlainListStyle())
        }
    }
}

struct secondView: View {
    
    @State var firstName: String
    
    var body: some View {
        NavigationView {
            Text(firstName)
                .padding()
        }
    }
    
}

谢谢!

在这种情况下您不需要 isActive,只需使用

List(myModelArray, id: \.self) { model in
    NavigationLink(destination: secondView(firstName: model.firstName)) { 
       Text(model.firstName) 
    }
}

并且您还没有在第二个视图中使用 NavigationView,即。

struct secondView: View {
    
    var firstName: String   // you don't need state here as well
    
    var body: some View {
        Text(firstName)
            .padding()
    }
}

这是因为只使用了一个状态navigationViewIsActive

所以当你点击导航 link 时,值将变为 True ,所有 link 将是 active

这种情况的解决方案是这样的:

  • 定义一个新的 State 来保存选定的模型值
  • 你只需要一个 NavigationLink ,然后将其设为 Hidden (将其放在 VStack 中)
  • List 中使用 Button 而不是 NavigationLink
  • 单击 Button 时:首先更改 selectedModel 值,然后激活导航链接 (true)

喜欢下面的代码 (Tested with IOS 14) :

import SwiftUI


struct Model: Equatable, Hashable {
    var userId: String
    var firstName: String
    var lastName: String
}


struct ContentView: View {
    
    @State var navigationViewIsActive: Bool = false
    @State var selectedModel : Model? = nil
    
    var myModelArray: [Model] = [
        Model(userId: "27e880a9-54c5-4da1-afff-05b4584b1d2f", firstName: "Leo", lastName: "Test"),
        Model(userId: "1050412a-cb12-4160-b7e4-2702ab8430c3", firstName: "Max", lastName: "Test"),
        Model(userId: "1050412a-cb12-4160-b7e4-2702ab8430c3", firstName: "Karl", lastName: "Test")]
    
    var body: some View {
        NavigationView {
            VStack {
                VStack {
                    if selectedModel != nil {
                        NavigationLink(destination: SecondView(firstName: selectedModel!.firstName), isActive: $navigationViewIsActive){ EmptyView() }
                    }
                }.hidden()
                
                List(myModelArray, id: \.self) { model in
                    Button(action: {
                        self.selectedModel = model
                        self.navigationViewIsActive = true
                    }, label: {
                        Text(model.firstName)
                    })
                }
                .listStyle(PlainListStyle())
            }
            
            
        }
    }
}

struct SecondView: View {
    
    @State var firstName: String
    
    var body: some View {
        NavigationView {
            Text(firstName)
                .padding()
        }
    }
    
}

struct Test_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

PS : 我写了这个 : How to navigate with SwiftUI ,它会帮助你理解在 swiftUI

中导航的方式