通过 NavigationLink - SwiftUI 对不同数据使用相同的视图

Using same View for different data via NavigationLink - SwiftUI

为了尽可能少地重现代码,我创建了一个 OwnListView,它得到一个 titlesubtitleList 个对象,我可以从中选择一个Continue button,但现在我有一个问题,即如何最好地使用 NavigationLinks 更改视图以获得具有不同数据的相同视图。

因为我想使用视图不只是2次,而是更频繁...

现在开始执行: 我想首先显示带有“最佳男性名字”的视图,然后是带有“最佳女性名字”的相同视图,然后是带有“最佳颜色”的相同视图,依此类推。

我没有找到完全适合我的问题 - 我希望有人能帮助我

这是我的 StartView,这是第一个视图,我的 ListModel 已初始化

struct StartView: View {
   
   @StateObject var listModel = ListModel()
   
   var body: some View {
       NavigationView{
           NavigationLink(destination: {
               OwnListView(listModel: listModel,
                           title: "MaleNames",
                           items: ["Todd", "Liam", "Noah", "Oliver", "James", "William"],
                           choosedItems: $listModel.maleNames)
           }, label: {
               Text("Start")
                   .bold()
           })
       }
   }
}

然后是我的ListView,我想从中得到几个,这样我就可以做一个“调查”或类似的事情:

struct OwnListView: View {

    //ListModel
    @ObservedObject var listModel: ListModel
    
    var title: String
    var items: [String]
    
    @Binding var choosedItems: [String]
    
    var body: some View {
        
        VStack{
            
            Text(title)
                .font(.largeTitle)
                .bold()
            
            ForEach(items, id: \.self){ item in
                
                let alreadyInList: Bool = choosedItems.contains(where: { [=11=] == item })
                
                Button(action: {
                    if alreadyInList {
                        choosedItems.removeAll(where: { [=11=] == item })
                    } else {
                        choosedItems.append(item)
                    }
                }, label: {
                    //Can be an own View, but for simplicity
                    ZStack{
                        Rectangle()
                            .fill(alreadyInList ? .black : .purple)
                            .frame(width: 250, height: 50)
                        
                        Text(item)
                            .bold()
                            .foregroundColor(.white)
                    }
                })
            }
            
            Spacer()
            
            //After Best Male Names - female names
            NavigationLink(destination: {
                OwnListView(listModel: listModel,
                            title: "Best Female Names",
                            items: ["Jessica", "Monica", "Stephanie"],
                            choosedItems: $listModel.femaleNames)
            }, label: {
                Text("Continue")
            })
            
            /*
            //After Best Female Names - colors
            NavigationLink(destination: {
             OwnListView(listModel: listModel,
                         title: "Best Colors",
                         items: ["Pink", "Blue", "Yellow", "Green"],
                         choosedItems: listModel.colors)
            }, label: {
                Text("Continue")
            })
             */
            
            Spacer()
            
        }.navigationBarTitleDisplayMode(.inline)
    }
}

只有一个视图可以重新加载的一种方法是动态定义其内容。可以使用枚举来保存调查的状态:

class ListModel: ObservableObject {
    // The enum is the list of tests
    enum Choosing {
        case male
        case female
        case color
        // Define each test title
        var title: String {
            switch self {
                case .male:
                    return "Male Names"
                case .female:
                    return "Female Names"
                case .color:
                    return "Color Names"
            }
        }
        // define each test possible values
        var items: [String] {
            switch self {
                case .male:
                    return ["Todd", "Liam", "Noah", "Oliver", "James", "William"]
                case .female:
                    return ["Jessica", "Monica", "Stephanie"]
                case .color:
                    return ["Pink", "Blue", "Yellow", "Green"]
            }
        }
        // choosing next test
        var next: Choosing? {
            switch self {
                case .male:
                    return .female
                case .female:
                    return .color
                case .color:
                    return nil
            }
        }
    }
    
    @Published var choosedItems: [Choosing:[String]] = [.male:[], .female:[], .color:[]]
}


struct StartView: View {
    @StateObject var listModel = ListModel()
    
    var body: some View {
        NavigationView{
            NavigationLink(destination: {
                // Just give model and first test
                OwnListView(listModel: listModel,
                            choosing: .male)
            }, label: {
                Text("Start")
                    .bold()
            })
        }
    }
}

普遍看法:

struct OwnListView: View {
    //ListModel
    @ObservedObject var listModel: ListModel
    
    var choosing: ListModel.Choosing
    // Use enum var to get title and items
    var title: String {
        choosing.title
    }
    var items: [String] {
        choosing.items
    }
    
    var body: some View {
        VStack{
            Text(title)
                .font(.largeTitle)
                .bold()
            
            ForEach(choosing.items, id: \.self){ item in
                // Use the current test result
                let alreadyInList: Bool = listModel.choosedItems[choosing]?.contains(where: { [=11=] == item }) ?? false
                
                Button(action: {
                    if alreadyInList {
                        listModel.choosedItems[choosing]?.removeAll(where: { [=11=] == item })
                    } else {
                        listModel.choosedItems[choosing]?.append(item)
                    }
                }, label: {
                    //Can be an own View, but for simplicity
                    ZStack{
                        Rectangle()
                            .fill(alreadyInList ? .black : .purple)
                            .frame(width: 250, height: 50)
                        
                        Text(item)
                            .bold()
                            .foregroundColor(.white)
                    }
                })
            }
            
            Spacer()
            
            // if still somthing test next
            if let next = choosing.next {
                NavigationLink(destination: {
                    OwnListView(listModel: listModel,
                                choosing: next)
                }, label: {
                    Text("Continue")
                })
            } else {
                // Here you can have a button to navigation link to go to end of survey
                Text("Finish")
            }
            
            Spacer()
            
        }.navigationBarTitleDisplayMode(.inline)
    }
}

注意:枚举、标题和值可以来自外部 json 文件以使其更通用。这只是一种方法。 要完成调查,只需完成枚举定义。