SwiftUI导航视图在层次结构中返回

4

我在导航视图层次结构上遇到了问题。

我的应用程序中所有的屏幕都使用相同的ViewModel。

当导航链接内的屏幕更新ViewModel(这里称为DataManager)时,导航视图会自动返回到第一个屏幕,就像按下“返回”按钮一样。

这是它的外观

我尽可能地精简了我的代码。

struct DataModel: Identifiable, Codable {
  var name: String
  
  var isPinned: Bool = false
  var id: String = UUID().uuidString
}

class DataManager: ObservableObject {
    @Published private(set) var allModules: [DataModel]
    
    var pinnedModules: [DataModel] {
        allModules.filter { $0.isPinned }
    }
    
    var otherModules: [DataModel] {
        allModules.filter { !$0.isPinned }
    }
    
    func pinModule(id: String) {
        if let moduleIndex = allModules.firstIndex(where: { $0.id == id }) {
            allModules[moduleIndex].isPinned = true
        }
    }
    
    func unpinModule(id: String) {
        if let moduleIndex = allModules.firstIndex(where: { $0.id == id }) {
            allModules[moduleIndex].isPinned = false
        }
    }
    
    static let instance = DataManager()
    
    fileprivate init() {
        allModules =
        [DataModel(name: "One"),
         DataModel(name: "Two"),
         DataModel(name: "Three"),
         DataModel(name: "Four"),
         DataModel(name: "Five")]
    }
}


struct ModulesList: View {
    @StateObject private var dataStorage = DataManager.instance
    
    
    var body: some View {
        NavigationView {
            List {
                Section("Pinned") {
                    ForEach(dataStorage.pinnedModules) { module in
                        ModulesListCell(module: module)
                    }
                }
                
                Section("Other") {
                    ForEach(dataStorage.otherModules) { module in
                        ModulesListCell(module: module)
                    }
                }
            }
        }
    }
    
    fileprivate struct ModulesListCell: View {
        let module: DataModel
        
        var body: some View {
            NavigationLink {
                SingleModuleScreen(module: module)
            } label: {
                Text(module.name)
            }
        }
    }
}

struct SingleModuleScreen: View {
    @State var module: DataModel
    @StateObject var dataStorage = DataManager.instance
    
    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                Text(module.name)
                    .font(.title)
                
                Button {
                    dataStorage.pinModule(id: module.id)
                } label: {
                    Text("Pin")
                }
            }
        }
    }
}

2个回答

2
当你点击 Pin 时,其他模块数组会重新创建,你无法从导航堆栈中找到你导航的视图。因此,自动返回是期望的行为。所以解决方案是:不要销毁创建 NavigationLink 的数组。创建一个临时发布的数组,从该数组加载其他模块,并在 onAppear 中更改数组,如下所示: 作为解决方法,在我的环境中运行: 在 DataManger 中添加以下行:
@Published var tempOtherModules:[DataModel] = []

将您的ModulesList更改如下

struct ModulesList: View {
    @StateObject private var dataStorage = DataManager.instance
    
    
    var body: some View {
        NavigationView {
            List {
                
                Section("Pinned") {
                    ForEach(dataStorage.pinnedModules) { module in
                        ModulesListCell(module: module)
                    }
                }
                
                Section("Other") {
                    ForEach(dataStorage.tempOtherModules) { module in
                        ModulesListCell(module: module)
                    }
                }
            }.onAppear {
                dataStorage.tempOtherModules = dataStorage.otherModules
            }
        }
    }
}

1
哇!这么简单明了,我甚至没有想到过...谢谢! - boring_ape

2
我猜测是因为当你的dataStorage发生变化时,ModulesList将被重新绘制,这导致所有当前的ModulesListCell从内存中删除。
你的单元格是NavigationLink,当它被销毁时,导航堆栈不会保留正在链接的屏幕。
我建议观看这个wwdc https://developer.apple.com/videos/play/wwdc2021/10022/,你将知道如何在数据变化时正确管理视图标识。

这是一段必看的视频。 - Tanvirgeek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接