SwiftUI 以编程方式选择列表项

use*_*617 5 xcode ios swiftui

我有一个带有基本列表/详细信息结构的 SwiftUI 应用程序。从模态表创建一个新项目。当我创建一个新项目并保存它时,我希望选择该列表项。实际上,如果在添加之前没有选择任何项目,则在添加之后不会选择任何项目。如果在添加之前选择了一个项目,则在添加之后选择了相同的项目。

我将包含 ContentView 的代码,但这确实是 List/Detail 的最简单示例。

struct ContentView: View {

    @ObservedObject var resortStore = ResortStore()
    @State private var addNewResort = false
    @State private var coverDeletedDetail = false

    @Environment(\.presentationMode) var presentationMode

    var body: some View {

        List {
            ForEach(resortStore.resorts) { resort in
                NavigationLink(destination: ResortView(resort: resort)) {

                    HStack(spacing: 20) {
                        Image("FlatheadLake1")
                        //bunch of modifiers

                        VStack(alignment: .leading, spacing: 10) {
                        //the cell contents
                        }
                    }
                }
            }
            .onDelete { indexSet in
                self.removeItems(at: [indexSet.first!])
                self.coverDeletedDetail.toggle()
            }

            if UIDevice.current.userInterfaceIdiom == .pad {
                NavigationLink(destination: WelcomeView(), isActive: self.$coverDeletedDetail) {
                    Text("")
                }
            }
        }//list
        .onAppear(perform: self.selectARow)
        .navigationBarTitle("Resorts")
        .navigationBarItems(leading:
        //buttons

    }//body

    func removeItems(at offsets: IndexSet) {
        resortStore.resorts.remove(atOffsets: offsets)
    }

    func selectARow() {
    //nothing that I have tried works here
        print("selectARow")
    }
}//struct
Run Code Online (Sandbox Code Playgroud)

再次 - 添加项目模式是非常基本的:

struct AddNewResort: View {
//bunch of properties

    var body: some View {
        VStack {
            Text("Add a Resort")
            VStack {
                TextField("Enter a name", text: $resortName)
                //the rest of the fields
            }
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .padding(EdgeInsets(top: 20, leading: 30, bottom: 20, trailing: 30))

            Button(action: {
                let newResort = Resort(id: UUID(), name: self.resortName, country: self.resortCountry, description: self.resortDescription, imageCredit: "Credit", price: Int(self.resortPriceString) ?? 0, size: Int(self.resortSizeString) ?? 0, snowDepth: 20, elevation: 3000, runs: 40, facilities: ["bar", "garage"])
                self.resortStore.resorts.append(newResort)
                self.presentationMode.wrappedValue.dismiss()
            }) {
                Text("Save Trip")
            }
            .padding(.trailing, 20)

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

显示问题 - 带有选择的列表:

在此处输入图片说明

创建新项目后的列表显示了先前的选择:

在此处输入图片说明

任何指导将不胜感激。Xcode 11.4

小智 5

我尝试尽可能地重构您的代码,以便它能够构建。这就是我最终得到的。我们有一个度假村列表,当新度假村保存在 AddNewResort 工作表中时,如果我们当前处于拆分视图(horizo​​ntalSizeClass 为常规),我们将选择新度假村,否则只需关闭该工作表。

import SwiftUI

class ResortStore: ObservableObject {
    @Published var resorts = [Resort(id: UUID(), name: "Resort 1")]
}

struct ContentView: View {
    @ObservedObject var resortStore = ResortStore()
    @State private var addingNewResort = false

    @State var selectedResortId: UUID? = nil

    var navigationLink: NavigationLink<EmptyView, ResortView>? {
        guard let selectedResortId = selectedResortId,
            let selectedResort = resortStore.resorts.first(where: {$0.id == selectedResortId}) else {
                return nil
        }

        return NavigationLink(
            destination: ResortView(resort: selectedResort),
            tag:  selectedResortId,
            selection: $selectedResortId
        ) {
            EmptyView()
        }
    }

    var body: some View {

        NavigationView {
            ZStack {
                navigationLink
                List {
                    ForEach(resortStore.resorts, id: \.self.id) { resort in
                        Button(action: {
                            self.selectedResortId = resort.id
                        }) {
                            Text(resort.name)
                        }
                        .listRowBackground(self.selectedResortId == resort.id ? Color.gray : Color(UIColor.systemBackground))
                    }

                }
            }
            .navigationBarTitle("Resorts")
            .navigationBarItems(trailing: Button("Add Resort") {
                self.addingNewResort = true
            })
                .sheet(isPresented: $addingNewResort) {
                    AddNewResort(selectedResortId: self.$selectedResortId)
                        .environmentObject(self.resortStore)
            }

            WelcomeView()
        }

    }

}

struct ResortView: View {
    let resort: Resort

    var body: some View {
        Text("Resort View for resort name: \(resort.name).")
    }
}


struct AddNewResort: View {
//bunch of properties

    @Binding var selectedResortId: UUID?

    @State var resortName = ""

    @Environment(\.presentationMode) var presentationMode
    @Environment(\.horizontalSizeClass) var horizontalSizeClass
    @EnvironmentObject var resortStore: ResortStore

    var body: some View {
        VStack {
            Text("Add a Resort")
            VStack {
                TextField("Enter a name", text: $resortName)
                //the rest of the fields
            }
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .padding(EdgeInsets(top: 20, leading: 30, bottom: 20, trailing: 30))

            Button(action: {
                let newResort = Resort(id: UUID(), name: self.resortName)
                self.resortStore.resorts.append(newResort)
                self.presentationMode.wrappedValue.dismiss()

                if self.horizontalSizeClass == .regular {
                    self.selectedResortId = newResort.id
                }

            }) {
                Text("Save Trip")
            }
            .padding(.trailing, 20)

        }
    }
}

struct WelcomeView: View {
    var body: some View {
        Text("Welcome View")
    }
}

struct Resort {
    var id: UUID
    var name: String
}
Run Code Online (Sandbox Code Playgroud)
  1. 我们需要跟踪 selectedResortId
  2. 我们创建一个不可见的 NavigationLink,它将以编程方式导航到所选的度假村
  3. 我们将列表行设置为按钮,以便用户可以通过点击该行来选择度假村

我开始撰写一系列有关 SwiftUI 列表视图中的导航的文章,在实现编程式导航时需要考虑很多要点。以下是我建议的描述此解决方案的内容:列表视图中的 SwiftUI 导航:编程导航。该解决方案目前适用于 iOS 13.4.1。SwiftUI 正在快速变化,因此我们必须不断检查。

这是我的上一篇文章,解释了为什么向每个列表行添加 NavigationLink 的更简单解决方案目前存在一些问题列表视图中的 SwiftUI 导航:探索可用选项

如果您有疑问,请告诉我,我很乐意尽我所能提供帮助。