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/

相关文章:

SwiftUI 列表未显示任何项目

arrays - 如何在 Swift 中压缩数组?

ios - 如何加载所有 View Controller Storyboard,但跳过自然顺序并直接转到特定 View ?

ios - 如何在每次切换文本时执行不同的 Action ?

xcode - SwiftUI:listRowInsets 未按预期工作

swiftui - 有没有办法在 SwiftUI 中的可搜索导航修改器上关闭自动更正/设置键盘类型

iOS 13.0 - 支持深色模式并支持 iOS 11 和 12 的最佳方法

ios - Health 处理多步骤源的方式与 HealthKit 不同——swift

ios - 如何实现CallKit : SwiftUI

SwiftUI - 单元格项目消失