SwiftUI: изменение источника ForEach или запроса выборки с помощью средства выбора (сегментировано)

Я новичок в SwiftUI и кодировании в целом, извините, если об этом уже говорилось раньше. Я искал об этом, но не смог найти достаточно ясного.

Пытаюсь сделать приложение для хранения заметок и задач. (Я не планирую выкладывать его в магазин, я слишком новичок для этого, но я действительно хочу изучить Swift, и работа над реальным приложением для меня более полезна, чем чтение об этом.) У меня есть объект под названием "Базовый" с 8 атрибутами и выбранным автоматическим определением класса Codegen. Я предпочитаю оставить это так, пожалуйста, без руководства.

У меня три запроса на выборку. Я получаю все данные из Core Data. Два других фильтруют один атрибут, называемый campoEstado. На данный момент в campoEstado я храню только одно из двух возможных значений в виде строк: "Activas" и "Pospuestas". В будущем я могу добавить больше, поэтому я не могу использовать для этого логическое значение.

Я получаю список, работающий с одним запросом на выборку. Но я не могу изменить этот источник, когда приложение работает. Я сделал Picker с.pickerStyle(SegmentedPickerStyle()), который показывает мне: Todo, Activas, Pospuestas. Когда пользователь выбирает одну из этих вкладок в средстве выбора, список должен измениться на:

  • Вкладка 1: Все задачи
  • Вкладка 2: отфильтрованный список, содержащий только задачи с campoEstado = "Activas" (вызывает запрос на выборку filterroActivas)
  • Вкладка 3: отфильтрованный список, содержащий только задачи с campoEstado = "Pospuestas" (вызывает запрос на выборку filterroPospuestas)

Как это должно выглядеть:

Мой код в ContentView:

    struct ContentView: View {    

@Environment(\.managedObjectContext) var moc    
    @FetchRequest(entity: Base.entity(), sortDescriptors: [
        NSSortDescriptor(keyPath: \Base.campoNota, ascending: true),
        NSSortDescriptor(keyPath: \Base.campoFechaCreacion, ascending: true)
    ], predicate: NSPredicate(format: "campoEstado == %@", "Activas")
    ) var filtroActivas: FetchedResults<Base>

    @FetchRequest(entity: Base.entity(), sortDescriptors: [
        NSSortDescriptor(keyPath: \Base.campoNota, ascending: true),
        NSSortDescriptor(keyPath: \Base.campoFechaCreacion, ascending: true)
    ], predicate: NSPredicate(format: "campoEstado == %@", "Pospuestas")
    ) var filtroPospuestas: FetchedResults<Base>

     @FetchRequest(entity: Base.entity(), sortDescriptors: [
        NSSortDescriptor(keyPath: \Base.campoNota, ascending: true),
        NSSortDescriptor(keyPath: \Base.campoFechaCreacion, ascending: true)
    ]
    ) var bases: FetchedResults<Base>

var body: some View {
        NavigationView {
            List {
                Picker("Solapas", selection: $selectorIndex) {
                    //This should connect to ForEach source, currently "bases"
                }
                .pickerStyle(SegmentedPickerStyle())
                
              
                ForEach(bases, id: \.self) { lista in
                    NavigationLink(destination: VistaEditar(base: lista)) {
                        Rectangle()
                        .foregroundColor(.gray)
                        .frame(width: 7, height: 50)
                        
                        VStack(alignment: .leading) {
                            Text(lista.campoNota ?? "Unknown title")
                                .font(.headline)
                            Text(lista.campoEstado ?? "Activas")
                        }
                    }
                }

У меня две проблемы:

  1. Я не знаю, как связать выбранную вкладку в средстве выбора с источником ForEach внутри списка

  2. Я заставил список работать для одного запроса на выборку, который приносит мне все записи в Core Data, но я не знаю, как изменить источник ForEach, когда приложение работает. Я пробовал использовать массив имен переменных для каждого из имен переменных запросов на выборку (баз, фильтроактивас и фильтропоспуэстас), помещая их в [], но это не сработало.

Я знаю, что это не изящно, мне просто нужно, чтобы сначала работало, а потом уже работало эффективность и элегантность. Я уверен, что есть какая-то глупость, которую я не вижу, но прошла неделя, и я в отчаянии.

Надеюсь, я был понятен, если вам нужна дополнительная информация, спросите. Если кто-нибудь может мне помочь, я был бы очень признателен. Заранее спасибо!

1 ответ

Я боюсь, что меня могут проголосовать против, потому что это не совсем полный ответ. Но у меня нет времени, и я хотел посмотреть, смогу ли я направить вас в правильном направлении.

Я считаю, что вы ищете массив массивов. АFetchedResultвернет необязательный массив, который вам нужно убедиться, что он не равен нулю. я использовалcompactMap в моем примере для генерации ненулевого массива из моих образцов дополнительных массивов, которые предназначены для имитации того, что вы получаете от своего @FetchRequestсвойства. Вы должны иметь возможность загрузить этот код в новый проект в Xcode, чтобы увидеть результаты. Опять же, это не полный ответ, но, надеюсь, он поможет вам в вашем проекте. Надеюсь, это поможет, продолжайте работать над этим, вы получите это!

struct ContentView: View {
// Sample data to mimic optional FetchedResults coming from CoreData.
// These are your @FetchRequest properties
let fetchedResultsBases: [String?] = ["Red", "Green", "Blue"]
let fetchedResultsFiltroPospuestas: [String?] = ["1", "2", "3"]
let fetchedResultsFiltroActivas: [String?] = ["☺️", "", ""]

// Options for your picker
let types = ["Bases", "Pospuestas", "Activas"]

@State private var groups = [[String]]()
@State private var selection = 0

var body: some View {
    NavigationView {
        VStack {
            Picker("Solapas", selection: $selection) {
                ForEach(0..<types.count, id: \.self) {
                    Text("\(self.types[$0])")
                }
            }.pickerStyle(SegmentedPickerStyle())

            List {
                ForEach(0..<groups.count, id: \.self) { group in
                    Text("\(self.groups[self.selection][group])")
                }
            }
        }
    }
    .onAppear(perform: {
        self.loadFetchedResults()
    })
} // This is the end of the View body

func loadFetchedResults() {
    // This is where you'll create your array of fetchedResults, then add it to the @State property.
    var fetchedResults = [[String]]()

    // Use compact map to remove any nil values.
    let bases = fetchedResultsBases.compactMap { $0 }
    let pospuestas = fetchedResultsFiltroPospuestas.compactMap { $0 }
    let filtroActivas = fetchedResultsFiltroActivas.compactMap { $0 }

    fetchedResults.append(bases)
    fetchedResults.append(pospuestas)
    fetchedResults.append(filtroActivas)

    groups = fetchedResults
}

} // This is the end of the ContentView struct
Другие вопросы по тегам