Расширяемый список в SwiftUI расширяется только один раз и не будет сокращаться - PullRequest
0 голосов
/ 23 сентября 2019

Я пытаюсь (и не могу!) Реализовать расширяемый список вопросов и ответов в SwiftUI.

struct FAQ: Equatable, Identifiable {
    static func ==(lhs: FAQ, rhs: FAQ) -> Bool {
        return lhs.id == rhs.id
    }
    let id = UUID()
    let question: String
    let answers: [String]
    var isExpanded: Bool = false
}

struct ContentView: View {
    @State private (set) var faqs: [FAQ] = [
        FAQ(question: "What is the fastest animal on land?", answers: ["The cheetah"]),
        FAQ(question: "What colours are in a rainbox?", answers: ["Red", "Orange", "Yellow", "Blue", "Indigo", "Violet"])
    ]

    var body: some View {
        List {
            ForEach(faqs) { faq in
                Section(header: Text(faq.question)
                    .onTapGesture {
                        if let index = self.faqs.firstIndex(of: faq) {
                            self.faqs[index].isExpanded.toggle()
                        }
                    }
                ) {
                    if faq.isExpanded {
                        ForEach(faq.answers, id: \.self) {
                            Text("• " + $0).font(.body)
                        }
                    }
                }
            }
        }
    }
}

Успешное нажатие на любой вопрос расширяет список представленных ответов, но повторное нажатие на тот же заголовок не сокращает ответы, а касание второго вопроса не расширяет эти ответы.

enter image description here

С некоторыми разумно расположенными print s я вижу, что isExpanded переключается на true при первом затронутом вопросе, но затем не переключается обратно на false.

Может кто-нибудь объяснить, что я делаю не так?

1 Ответ

1 голос
/ 23 сентября 2019

Проблема с вашей @State var faq: [FAQ] строкой.Оболочка свойства @State позволяет вашему представлению следить за изменениями в вашем массиве, но изменение свойства одного из элементов массива не считается изменением в массиве.

Вместо использования переменной состояния,вы, вероятно, хотите создать модель небольшого вида, например:

class ViewModel: ObservableObject {
    @Published var faqs: [FAQ] = [
           FAQ(question: "What is the fastest animal on land?", answers: ["The cheetah"]),
           FAQ(question: "What colours are in a rainbox?", answers: ["Red", "Orange", "Yellow", "Blue", "Indigo", "Violet"])
       ]
}

и обновить ваш ContentView:

struct ContentView: View {
    @ObservedObject var model = ViewModel()

    var body: some View {
        List {
            ForEach(model.faqs.indices) { index in
                Section(header: Text(self.model.faqs[index].question)
                    .onTapGesture {
                        self.model.faqs[index].isExpanded.toggle()
                    }
                ) {
                    if self.model.faqs[index].isExpanded {
                        ForEach(self.model.faqs[index].answers, id: \.self) {
                            Text("• " + $0).font(.body)
                        }
                    }
                }
            }
        }
    }
}

Оболочка свойства @ObservedObject в вашем ContentView теперь следит заany меняет свой объект ViewModel, и оболочка @Published сообщает классу ViewModel о том, что происходит с массивом, включая изменения его элементов.

...