SwiftUI программно выбрать элемент списка - PullRequest
2 голосов
/ 06 апреля 2020

У меня есть приложение SwiftUI с базовой c структурой списка / детализации. Новый элемент создается из модального листа. Когда я создаю новый элемент и сохраняю его, я хочу, чтобы был выбран этот элемент списка. Таким образом, если ни один элемент не выбран перед добавлением, ни один элемент не выбирается после добавления. Если элемент выбран перед добавлением, тот же элемент выбирается после добавления.

Я включу код для 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

И снова - модальность добавляемого элемента чрезвычайно важна c:

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)

        }
    }
}

Чтобы показать проблему - Список с выбором:

enter image description here

Список после создания нового элемента с указанием предыдущего выбора:

enter image description here

Будем благодарны за любые указания. Xcode 11,4

1 Ответ

1 голос
/ 04 мая 2020

Я пытался воссоздать ваш код так близко, как мог, чтобы он собирался. Вот что я имею в итоге. У нас есть список курортов, и когда новый курорт сохраняется на листе AddNewResort, если мы в данный момент находимся в режиме разделенного просмотра (горизонтальный размер класса является обычным), мы выберем новый курорт, в противном случае просто отклоним лист.

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. Нам нужно отслеживать выбранныйResortId
  2. Мы создаем невидимую NavigationLink, которая программно будет перемещаться к выбранному курорту
  3. Мы делаем наш список строк кнопкой, чтобы пользователь может выбрать курорт, нажав на строку

. Я начал писать серию статей о навигации в представлении списка SwiftUI, при реализации программной навигации c необходимо учитывать множество моментов. Вот то, что описывает это решение, которое я предлагаю: Навигация SwiftUI в представлении списка: Programmati c Навигация . Это решение работает в данный момент на iOS 13.4.1. SwiftUI быстро меняется, поэтому мы должны продолжать проверять.

И вот моя предыдущая статья, которая объясняет, почему более простое решение добавления NavigationLink в каждую строку списка имеет некоторые проблемы в данный момент SwiftUI Навигация в виде списка: изучение доступных опций

Дайте мне знать, если у вас есть вопросы, я буду рад помочь, где смогу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...