swift - 如果列表顺序更改,SwiftUI NavigationView 中的选择会丢失

标签 swift swiftui swiftui-list swiftui-navigationlink

这是测试数据模型:

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 NavigationViewList似乎失去了它的选择,弹出 View ,然后再次推送它:
NavigationView losing selection
这是预期的行为还是 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/

相关文章:

ios - 停止从 webview 进行深层链接导航

ios - 从 Apple 登录注销

swift - ForEach 循环中的 VStack 不考虑 WatchOS 中的对齐参数

swift - SwiftUI `@State` 关键字有什么作用?

swift - 需要双击才能从详细信息 View 导航到 ListView

swift - 为什么我的 SwiftUI 列表再次追加所有对象而不是更新现有对象?

objective-c - 将 SKLabelNode 设置为 SKSpriteNode Swift 的中心

ios - 我想更改 UINavigationBar 的高度并添加标题..为什么这么难?

ios - 如何在使用它的 ViewController 上调整自定义(在单独的文件中创建)UIView 高度?

swiftui - 在 SwiftUI 中,如何在显示时为按钮偏移设置动画