这是测试数据模型:
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()
}
}
这是我的内容 View ,带有 NavigationLink
和一个带有颠倒项目顺序按钮的详细 View :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
似乎失去了它的选择,弹出 View ,然后再次推送它:这是预期的行为还是 SwiftUI 中的错误?有解决方法吗?我希望细节 View 保持原样,无需重新加载。
最佳答案
您需要指定一个显式 id
为您 ForEach
环形。
如果您使用静态 ForEach
(没有 id
参数)您的 View 被重建,因为数据( 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")
}
}
}
但是,此方法仅在所选项目的原始位置保持不变时才有效。在这个例子中执行
update()
从项目 1 的详细信息屏幕不会弹出 NavigationLink。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")
}
}
}
关于swift - 如果列表顺序更改,SwiftUI NavigationView 中的选择会丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62738861/