简体   繁体   English

SwiftUI:可以访问祖先自定义的@EnvironmentObject吗? 如果是,怎么办?

[英]SwiftUI : possible to access ancestor custom `@EnvironmentObject`? If yes, how?

(Using Xcode 11 beta 7) is it possible to access custom EnvironmentObject of ancestors? (使用Xcode 11 beta 7)是否可以访问祖先的自定义EnvironmentObject? If so how? 如果可以,怎么办? And using unlimited depth? 并使用无限深度?

Let's say we have many levels of depth in our navigation, eg 假设我们在导航中有很多深度层次,例如

UIScene -> MainView -> TabView (which contains a tab:) -> SettingsView -> AboutView -> AppVersionView UIScene-> MainView-> TabView(包含一个选项卡:)-> SettingsView-> AboutView-> AppVersionView

Starting counting MainView as depth level 1, and not coubting TabView, our AppVersionView is at depth level 4 in our navigationstack. 开始将MainView视为深度级别1,而不考虑TabView,我们的AppVersionView在导航堆栈中处于深度级别4。

Let's say we need to use some custom dependency, eg a RESTClient or whatever in AppVersionView. 假设我们需要使用一些自定义的依赖项,例如RESTClient或AppVersionView中的任何内容。 What this depedency is is irrelevant. 这种依赖是无关紧要的。 What is relevant is that our SceneDelegate class instantiates this depedency and the view at depth 1 (MainView) declares it as an @EnvirontmentObject to get it injected. 与此相关的是,我们的SceneDelegate类实例化了此依赖关系,深度为1的视图(MainView)将其声明为@EnvirontmentObject进行注入。

My current solution is that MainView "manually" forwards it by injecting it down to the next view in the stack, the SettingsView. 我当前的解决方案是MainView通过将其向下注入堆栈中的下一个视图SettingsView来“手动”转发。 And in the SettingsView I manually forward it again etc. 在SettingsView中,我再次手动转发它,等等。

This is a simplified example, in fact I have multiple dependencies throughout my SwiftUI app , being used and different layers throughout the navigation stack. 这是一个简化的示例,实际上,我在整个SwiftUI应用程序中都存在多个依赖关系,正在使用它们,并且在整个导航堆栈中具有不同的层次。

My thought was if it is possible to read/access these injected EnvironmentObjects somehow? 我的想法是,是否有可能以某种方式读取/访问这些注入的EnvironmentObject? In best case scenario recursively from any earlier ancestor. 在最佳情况下,从任何较早的祖先递归地进行。

If I have understood SwiftUI correctly, that is the case with ViewModifiers. 如果我正确理解了SwiftUI,那么ViewModifiers就是这种情况。 If I add the ViewModifier .foregroundColor(.red) to MainView, it should be passed as a system wide default color through out the app (inherited). 如果将ViewModifier .foregroundColor(.red) .red .foregroundColor(.red)添加到MainView,则应将其作为系统范围的默认颜色通过整个应用程序传递(继承)。

I was hoping the same thing could be done with custom EnvironmentObject. 我希望使用自定义的EnvironmentObject可以完成同样的事情。 And I know we can access predefined (non-custom) EnvironmentValues , in our views like this example from Mecid's great blog: 而且我知道我们可以从Mecid的出色博客的示例中访问预定义(非自定义)的EnvironmentValues

struct ButtonsView: View {
@Environment(\.sizeCategory) var sizeCategory

var body: some View {
    Group {
        if sizeCategory == .accessibilityExtraExtraExtraLarge {
            VStack {
                buttons
            }
        } else {
            HStack {
                buttons
            }
        }
    }
}

} }

An object put into the environment using the environmentObject modifier is passed down the view hierarchy, through TabView and NavigationView , to all descendant views. 使用environmentObject修饰符放入环境中的对象通过TabViewNavigationView向下传递到所有后代视图的视图层次结构中。 You don't have to do anything special (like manually forwarding it) to make this happen. 您不必做任何特殊的事情(例如手动转发它)就可以做到这一点。

In this example, in SceneDelegate , I'll store a model object in the environment of the MainView using the environmentObject modifier. 在此示例中,在SceneDelegate ,我将使用environmentObject修饰符将模型对象存储在MainViewenvironmentObject The model object has an appVersion string property. 模型对象具有appVersion字符串属性。 I'll access the model object using the @EnvironmentObject attribute in AppVersionView and use the model's appVersion to populate a Text subview. 我将使用访问模型对象@EnvironmentObject在属性AppVersionView和使用模型的appVersion来填充Text子视图。

在此处输入图片说明

Here's the code: 这是代码:

import UIKit
import SwiftUI

class Model: ObservableObject {
    @Published var appVersion: String = "version-1"
}

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = scene as? UIWindowScene else { return }

        let model = Model()
        let contentView = MainView().environmentObject(model)
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: contentView)
        self.window = window
        window.makeKeyAndVisible()
    }
}

struct MainView: View {
    var body: some View {
        TabView {
            NavigationView {
                SettingsView()
            }
            .tabItem {
                Image(systemName: "gear")
                Text("Settings") }
        }
    }
}

struct SettingsView: View {
    var body: some View {
        List {
            NavigationLink("About", destination: AboutView())
        }
    }
}

struct AboutView: View {
    var body: some View {
        List {
            NavigationLink("App Version", destination: AppVersionView())
        }
    }
}

struct AppVersionView: View {
    @EnvironmentObject var model: Model

    var body: some View {
        VStack {
            Text("App Version View")
            Text(model.appVersion)
        }
        .padding()
        .border(Color.black)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM