这是测试数据模型:
class Item: Identifiable {
let name: String
init( n: Int) {
self.name = "\(n)"
}
}
class Storage: ObservableObject {
@Published var items = [Item( n: 1), Item( n: 2)]
func reverse() {
items = self.items.reversed()
}
}
这是我的内容视图,其中包含一个NavigationLink
和一个详细视图,其中包含一个用于反转项目顺序的按钮:
struct ContentView: View {
@ObservedObject
var storage = Storage()
var body: some View {
NavigationView {
List {
ForEach( storage.items) { item in
NavigationLink( destination: Button( action: {
self.storage.reverse()
}) {
Text("Reverse")
}) {
Text( item.name).padding()
}
}
}
}
}
}
现在,如果我点击Reverse
,则NavigationView
或List
似乎会丢失选择,弹出视图,然后再次按下:
这是预期的行为还是SwiftUI中的错误?有解决方法吗?我希望细节视图可以保持原样,而无需重新加载。
答案 0 :(得分:2)
您需要为id
循环指定一个明确的ForEach
。
如果您使用静态ForEach
(不使用id
参数),则由于数据(storage.items
)发生了更改,因此将重建视图。
尝试以下操作:
struct ContentView: View {
@ObservedObject
var storage = Storage()
var body: some View {
NavigationView {
List {
ForEach(storage.items, id:\.name) { item in // <- add `id` parameter
NavigationLink(destination: self.destinationView) {
Text(item.name).padding()
}
}
}
}
}
var destinationView: some View {
Button(action: {
self.storage.reverse()
}) {
Text("Reverse")
}
}
}
但是,此方法仅在保持所选项目的原始位置的情况下有效。
在此示例中,从详细信息屏幕为项目1执行update()
不会弹出导航链接。
class Storage: ObservableObject {
@Published var items = [Item(n: 1), Item(n: 2)]
func update() {
items = [Item(n: 1), Item(n: 3)]
}
}
这里是一种解决方法,可以使其正常工作(使用空的NavigationLink
):
struct ContentView: View {
@ObservedObject var storage = Storage()
@State var isLinkActive = false
var body: some View {
NavigationView {
VStack {
List {
ForEach(storage.items, id:\.name) { item in
Button(action: {
self.isLinkActive = true
}) {
Text(item.name).padding()
}
}
}
NavigationLink(destination: self.destinationView, isActive: $isLinkActive) {
EmptyView()
}
}
}
}
var destinationView: some View {
Button(action: {
self.storage.reverse()
}) {
Text("Reverse")
}
}
}