简体   繁体   English

SwiftUI 以编程方式 Select 列表项

[英]SwiftUI Programmatically Select List Item

I have a SwiftUI app with a basic List/Detail structure.我有一个具有基本列表/详细信息结构的 SwiftUI 应用程序。 A new item is created from a modal sheet.从模态表创建一个新项目。 When I create a new item and save it I want THAT list item to be selected.当我创建一个新项目并保存它时,我希望选择那个列表项目。 As it is, if no item is selected before an add, no item is selected after an add.事实上,如果在添加之前没有选择任何项目,那么在添加之后没有选择任何项目。 If an item is selected before an add, that same item is selected after the add.如果在添加之前选择了一个项目,则在添加之后选择相同的项目。

I'll include code for the ContentView, but this is really the simplest example of List/Detail.我将包含 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

And again - the add item modal is extremely basic:再一次 - 添加项目模式非常基本:

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)

        }
    }
}

To show the issue - The list with a selection:显示问题 - 带有选择的列表:

在此处输入图像描述

The list after a new item created showing the previous selection:创建新项目后的列表显示先前的选择:

在此处输入图像描述

Any guidance would be appreciated.任何指导将不胜感激。 Xcode 11.4 Xcode 11.4

I tried to reconstitute your code as closely as could so that it builds.我试图尽可能地重构你的代码,以便它能够构建。 Here is what I have in the end.这就是我到底有什么。 We have a list of resorts and when a new resort is saved in the AddNewResort sheet, if we are currently in split view (horizontalSizeClass is regular), we will select the new resort, otherwise just dismiss the sheet.我们有一个度假村列表,当一个新的度假村保存在 AddNewResort 工作表中时,如果我们当前处于拆分视图(horizontalSizeClass 是常规的),我们将 select 新的度假村,否则只是关闭工作表。

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
}
  1. We need to keep track of the selectedResortId我们需要跟踪 selectedResortId
  2. We create an invisible NavigationLink that will programmatically navigate to the selected resort我们创建了一个不可见的 NavigationLink,它将以编程方式导航到选定的度假村
  3. We make our list row a Button, so that the user can select a resort by tapping on the row我们将列表行设为 Button,以便用户可以通过点击该行 select 成为度假村

I started writing a series of articles about navigation in SwiftUI List view, there are a lot of points to consider while implementing programmatic navigation.我开始在 SwiftUI 列表视图中写一系列关于导航的文章,在实现程序化导航时需要考虑很多点。 Here is the one that describes this solution that I'm suggesting: SwiftUI Navigation in List View: Programmatic Navigation .这是描述我建议的解决方案的一个: SwiftUI Navigation in List View: Programmatic Navigation This solution works at the moment on iOS 13.4.1.该解决方案目前适用于 iOS 13.4.1。 SwiftUI is changing rapidly, so we have to keep on checking. SwiftUI 变化很快,所以我们必须继续检查。

And here is my previous article that explains why a more simple solution of adding a NavigationLink to each List row has some problems at the moment SwiftUI Navigation in List View: Exploring Available Options这是我之前的文章,它解释了为什么向每个列表行添加 NavigationLink 的更简单的解决方案目前存在一些问题SwiftUI 列表视图中的导航:探索可用选项

Let me know if you have questions, I'd be happy to help where I can.如果您有任何问题,请告诉我,我很乐意尽我所能提供帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM