SwiftUI NavigationView 在数据源完成加载时弹出自身
SwiftUI NavigationView pop itself when a datasource is finished loading
假设您在屏幕 A 时正在从网络加载一些数据,这需要一些时间。在等待期间,您可以使用 NavigationLink 导航到其他屏幕。因此,此时您在屏幕 B,然后来自网络的数据已完成加载并将值发送回屏幕 A 中的数据源。NavigationView 会自动弹出,因此您无意中回到了屏幕 A。你有什么主意吗?谢谢
例子
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
NavigationView {
List(viewModel.dataSource, id: \.self) { item in
NavigationLink(destination: Text("\(item)")) {
Text("\(item)")
.padding()
}
}
}
}
}
class ViewModel: ObservableObject {
@Published private(set) var dataSource = [1, 2, 3, 4, 5]
init() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { // simulate calling webservice
self.dataSource[0] = 99
}
}
}
发生这种情况是因为您将 id
指定为 item
本身,当列表更新时不再有原始项目,因此它关闭
如果您只想修改没有 adding/removing/reordering 的项目,您可以将项目 ID 设为索引:
NavigationView {
List(viewModel.dataSource.indices, id: \.self) { i in
let item = viewModel.dataSource[i]
NavigationLink(destination: Text("\(item)")) {
Text("\(item)")
.padding()
}
}
}
但是对于更复杂的数据,您需要让您的项目 Identifiable
具有唯一的 ID,这样您就不会遇到这样的问题。看看这个例子:
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
NavigationView {
List(viewModel.dataSource) { item in
NavigationLink(destination: Text("\(item.value)")) {
Text("\(item.value)")
.padding()
}
}
}
}
}
class ViewModel: ObservableObject {
@Published private(set) var dataSource: [Item] = [1, 2, 3, 4, 5]
init() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [self] in // simulate calling webservice
// you're modifying value but id stays the same
self.dataSource[0].value = 99
}
}
}
struct Item: Identifiable, ExpressibleByIntegerLiteral {
let id = UUID()
var value: Int
init(integerLiteral value: IntegerLiteralType) {
self.value = value
}
}
假设您在屏幕 A 时正在从网络加载一些数据,这需要一些时间。在等待期间,您可以使用 NavigationLink 导航到其他屏幕。因此,此时您在屏幕 B,然后来自网络的数据已完成加载并将值发送回屏幕 A 中的数据源。NavigationView 会自动弹出,因此您无意中回到了屏幕 A。你有什么主意吗?谢谢
例子
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
NavigationView {
List(viewModel.dataSource, id: \.self) { item in
NavigationLink(destination: Text("\(item)")) {
Text("\(item)")
.padding()
}
}
}
}
}
class ViewModel: ObservableObject {
@Published private(set) var dataSource = [1, 2, 3, 4, 5]
init() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { // simulate calling webservice
self.dataSource[0] = 99
}
}
}
发生这种情况是因为您将 id
指定为 item
本身,当列表更新时不再有原始项目,因此它关闭
如果您只想修改没有 adding/removing/reordering 的项目,您可以将项目 ID 设为索引:
NavigationView {
List(viewModel.dataSource.indices, id: \.self) { i in
let item = viewModel.dataSource[i]
NavigationLink(destination: Text("\(item)")) {
Text("\(item)")
.padding()
}
}
}
但是对于更复杂的数据,您需要让您的项目 Identifiable
具有唯一的 ID,这样您就不会遇到这样的问题。看看这个例子:
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
NavigationView {
List(viewModel.dataSource) { item in
NavigationLink(destination: Text("\(item.value)")) {
Text("\(item.value)")
.padding()
}
}
}
}
}
class ViewModel: ObservableObject {
@Published private(set) var dataSource: [Item] = [1, 2, 3, 4, 5]
init() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [self] in // simulate calling webservice
// you're modifying value but id stays the same
self.dataSource[0].value = 99
}
}
}
struct Item: Identifiable, ExpressibleByIntegerLiteral {
let id = UUID()
var value: Int
init(integerLiteral value: IntegerLiteralType) {
self.value = value
}
}