我希望有人可以帮助我了解正在发生的事情以及为什么 SwiftUI 在这种情况下会表现得如此。
我最初尝试创建一个带有选择器的菜单,其中有一个日历列表供用户选择。对我来说重要的是显示一个彩色圆圈来指示日历的颜色以及标题。当时,我不知道如何让选择器菜单中的图标着色。所以,我认为带有列表的自定义弹出窗口会起作用。这就是让我发现这个问题的原因。
State
属性,可以在获取数据后保存视图中的数据.task
修饰符内部获取的(也尝试在 Task
内使用 onAppear
)VStack
组成的视图,其中包含触发弹出窗口的按钮以及充当菜单的选择器。两者都填充了相同的数据当选择器被注释掉时,弹出窗口始终显示为空,但它保留了一个框架。当选择器取消注释时,数据不仅会显示在选择器中,还会显示在弹出窗口中。这就是我真正难住的地方。为什么只有当选择器也在那里时才会填充弹出窗口中的列表?
onAppear
代替 .task
VStack
代替 List
可以轻松复制并亲自尝试
import SwiftUI
struct TestView: View {
let dataManager = DataManager()
@State private var items: [DataItem] = []
@State private var popoverIsPresented = false
var body: some View {
VStack {
Button {
popoverIsPresented = true
} label: {
Text("Choose Item")
}
.popover(isPresented: $popoverIsPresented, content: {
List {
ForEach(items) { item in
Text(item.title)
}
}
})
// List {
// ForEach(items) { item in
// Text(item.title)
// }
// }
}
.task { items = await dataManager.fetchData() }
}
}
#Preview {
TestView()
.frame(minWidth: 300, minHeight: 300)
}
struct DataItem: Identifiable {
let id = UUID()
let title: String
}
class DataManager {
func fetchData() async -> [DataItem] {
Array(repeating: .init(title: "This is an example item"), count: 10)
}
}
State
属性更改,弹出窗口就不会更新(我认为这将是一个错误)如果我理解正确的话,当您引用 picker 时,您实际上指的是示例中的
List
,对吗?
我能够通过取消注释
List
来重现该问题。但是,控制台中出现错误:
ForEach
:ID 1582CFA9-24C2-49BE-93DF-1D8B5FB949EA 在集合中多次出现,这将给出未定义的结果!
要解决此问题,需要以不同的方式构建虚拟数组。例如:
func fetchData() async -> [DataItem] {
// Array(repeating: .init(title: "This is an example item"), count: 10)
var result = [DataItem]()
for n in 0..<10 {
result.append(DataItem(title: "This is an example item \(n)"))
}
return result
}
当
List
被注释掉时,Popover
保持为空,正如您所描述的。我的猜测是,当将数组分配给状态变量时,视图的 body
不会被刷新,因为没有任何可见内容依赖于状态变量。正如您所建议的,这可能确实是一个错误。
作为解决方法,请尝试以某种方式使
body
依赖于状态变量。例如,您可以将项目计数显示为 Text
后面隐藏的 Button
元素:
Button {
popoverIsPresented = true
} label: {
Text("Choose Item")
}
.background { Text("\(items.count)").hidden() } // 👈 ADDED
.popover(isPresented: $popoverIsPresented) {
List {
ForEach(items) { item in
Text(item.title)
}
}
}
关于原来的要求:
对我来说重要的是显示一个彩色圆圈来指示日历的颜色以及标题。
👉 使用 Rectangle() 而不是 Text() 的 SwiftUI Picker 问题的答案展示了如何做到这一点。