【问题标题】:SwiftUI Navigation View goes back in hierarchySwiftUI 导航视图返回层次结构
【发布时间】:2022-03-04 14:23:03
【问题描述】:

导航视图层次结构有问题。

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

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

Here's what it looks like

我试图尽可能地缩减我的代码

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")
                }
            }
        }
    }
}

【问题讨论】:

    标签: swift swiftui swiftui-list swiftui-navigationlink swiftui-navigationview


    【解决方案1】:

    我可以猜到,因为当您的dataStorage 更改时,ModulesList 将被重新绘制,这会导致所有当前的ModulesListCell 从内存中删除。

    您的单元格是NavigationLink,当它被破坏时,导航堆栈不会保留正在链接的屏幕。

    我建议您观看此 wwdc https://developer.apple.com/videos/play/wwdc2021/10022/,您将知道如何在数据更改时正确管理您的视图身份。

    【讨论】:

    • 这是一个必须观看的视频。
    【解决方案2】:

    当您点击 Pin 时,将重新创建您的 otherModules 数组,并且您在导航堆栈中没有您导航的视图。因此,您将自动返回,这是所需的行为。所以解决方案是不要破坏创建 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
                }
            }
        }
    }
    

    【讨论】:

    • 哇!它是如此简单,但我什至没有考虑过......谢谢!
    猜你喜欢
    • 2020-01-10
    • 2020-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-21
    相关资源
    最近更新 更多