我正在尝试(但失败了!)在 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)
}
}
}
}
}
}
}
成功点击任何问题都会将答案展开,但再次点击同一个标题不会缩小答案,点击第二个问题也不会展开这些答案。
通过一些巧妙放置的 print
,我可以看到 isExpanded
在第一个问题被点击时切换到 true
,但随后不会t 切换回 false
。
有人可以解释我做错了什么吗?
最佳答案
问题出在您的 @State var faq: [FAQ]
行。 @State
属性包装器允许您的 View 监视数组中的更改,但更改数组元素之一的属性不算作数组中的更改。
您可能不想使用状态变量,而是想创建一个小 View 模型,如下所示:
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)
}
}
}
}
}
}
}
ContentView
中的 @ObservedObject
属性包装器现在监视其 ViewModel
对象宣布的任何更改,并且 @Published
包装器告诉 ViewModel
类宣布数组发生的任何事情,包括对其元素的更改。
关于swiftui - SwiftUI 中的可扩展列表只会扩展一次,不会收缩,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58064377/