【问题标题】:EnvironmentObject refresh/hand over problems using NavigationLinkEnvironmentObject 使用 NavigationLink 刷新/移交问题
【发布时间】:2020-10-22 06:29:42
【问题描述】:

我目前正在 macOS Catalina 上的 XCode 11.5 中使用 Swift/SwiftUI 为 watchOS 6(独立应用程序)开发应用程序。

在用户可以使用我的应用之前,需要一个配置过程。由于配置过程由几个不同的视图组成,这些视图一个接一个地显示,我通过导航链接实现了这一点。

配置过程完成后,用户应单击按钮返回“主”应用程序(主视图)。为了控制同一层级的视图,我的计划是结合“控制视图”使用 EnvironmentObject(据我了解,注入后的 EnvironmentObject 将移交给子视图,子视图可以使用 EnvironmentObject)它控制视图的显示。因此,我按照教程:https://blckbirds.com/post/how-to-navigate-between-views-in-swiftui-by-using-an-environmentobject/

这是我的代码:

ContentView.swift

struct ContentView: View {
    var body: some View {
        ContentViewManager().environmentObject(AppStateControl())        
    }
}

struct ContentViewManager: View {
    @EnvironmentObject var appStateControl: AppStateControl
    
    var body: some View {
        VStack {
            if(appStateControl.callView == "AppConfig") {
                AppConfig()
            }
            if(appStateControl.callView == "AppMain") {
                AppMain()
            }
        }
    }
}

AppStateControl.swift

class AppStateControl: ObservableObject {
    @Published var callView: String = "AppConfig"
}

AppConfig.swift

struct AppConfig: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Main")
            NavigationLink(destination: DetailView1().environmentObject(appStateControl)) {
                Text("Show Detail View 1")
            }
        }
    }
}

struct DetailView1: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Detail View 1")
            NavigationLink(destination: DetailView2().environmentObject(appStateControl)) {
                Text("Show Detail View 2")
            }
        }
    }
}

struct DetailView2: View {
    @EnvironmentObject var appStateControl: AppStateControl
    var body: some View {
        VStack {
            Text("App Config Detail View 2")
            Button(action: {
                self.appStateControl.callView = "AppMain"
            }) {
             Text("Go to main App")
            }
        }
    }
}

AppMain.swift

struct AppMain: View {
    var body: some View {
        Text("Main App")
    }
}

在我的代码的早期版本中(始终没有移交 EnvironmentObject)我收到运行时错误(“线程 1:致命错误:未找到 AppStateControl 类型的 ObservableObject。A View.environmentObject( _:) 作为该视图的祖先,AppStateControl 可能会丢失。") 由 AppConfig.swift 中的第 41 行引起。在互联网上,我读到这可能是 NavigationLink 的错误(参见:https://www.hackingwithswift.com/forums/swiftui/environment-object-not-being-inherited-by-child-sometimes-and-app-crashes/269https://twitter.com/twostraws/status/1146315336578469888)。因此,建议将 EnvironmentObject 显式传递到 NavigationLink 的目的地(以上实现)。不幸的是,这也不起作用,而是单击 "DetailView2" 中的按钮“转到主应用程序”会导致视图 "DetailView1" 而不是 “AppMain”.

任何想法如何解决这个问题?对我来说,通过导航链接调用的视图中 EnvironmentObject 的更改似乎不会刷新视图(正确)。

提前致谢。

【问题讨论】:

    标签: xcode data-binding swiftui watchos swiftui-navigationlink


    【解决方案1】:

    其中一种解决方案是创建一个变量来控制是否显示导航堆栈。

    class AppStateControl: ObservableObject {
        ...
        @Published var isDetailActive = false // <- add this
    }
    

    然后你可以通过设置isActive参数来使用这个变量来控制第一个NavigationLink。您还需要将.isDetailLink(false) 添加到所有后续链接。

    堆栈中的第一个链接:

    NavigationLink(destination: DetailView1().environmentObject(appStateControl), isActive: self.$appStateControl.isDetailActive) {
        Text("Show Detail View 1")
    }
    .isDetailLink(false)
    

    所有其他链接:

    NavigationLink(destination: DetailView2().environmentObject(appStateControl)) {
        Text("Show Detail View 2")
    }
    .isDetailLink(false)
    

    然后只需将 isDetailActive 设置为 false 即可弹出所有 NavigationLink 并返回主视图:

    Button(action: {
        self.appStateControl.callView = "AppMain"
        self.appStateControl.isDetailActive = false // <- add this
    }) {
        Text("Go to main App")
    }
    

    【讨论】:

    • 感谢您的快速回复!我刚刚实现了解决方案,但是,应用程序的行为方式与以前相同。不幸的是, .isDetailLink(false) 在 watchOS 中不可用。关于如何解决这个问题或为什么我的应用会出现这种行为的任何其他想法?
    • @JPF 哦,我明白了,我的错。你可以看到这个问题SwiftUI: How to pop to Root view,我认为这个answer 解释了如何让它在watchOS 上运行。思路是一样的——你需要回到导航栈的根目录来显示AppMain而不是AppConfig
    猜你喜欢
    • 2020-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多