【问题标题】:`SwiftUI` - `EnvironmentObject`s, `EnvironmentValues` does not propagate to modally presented `UIViewController``SwiftUI` - `EnvironmentObject`s,`EnvironmentValues` 不会传播到模态呈现的 `UIViewController`
【发布时间】:2022-01-24 04:51:01
【问题描述】:

SwiftUIEnvironmentObjects 和 EnvironmentValues 如果视图层次结构设置正确,则应该传播给子级 - 这对于纯 SwiftUI 视图层次结构的情况似乎是正确的。当父视图控制器字面上包含其子视图时(例如,UITabViewControllerUINavigationController、...),与 UIKit 混合大小写也是如此。

但在SwiftUI 视图层次结构上以模态方式呈现的UIKit 视图控制器不会从其父级获取环境。这是我的设置。

// ContentView
struct ContentView: View {

    var body: some View {
        TabBarController()
            .environment(\.lineLimit, 3) // override default value of lineLimit
    }

}

// TabBarController
struct TabBarController: UIViewControllerRepresentable {

    typealias UIViewControllerType = UITabBarController

    func makeUIViewController(context: Context) -> UIViewControllerType {
        let uiViewController = UITabBarController()
        uiViewController.setViewControllers([
            UIHostingController(rootView: FooBar()),
            UIHostingController(rootView: FooBar()),
            UIHostingController(rootView: FooBar())
        ], animated: false)
        return uiViewController
    }

    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        // For test purpose, present view controller modally
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            uiViewController.present(UIHostingController(rootView: FooBar()), animated: true)
        }
    }

}

// FooBar
struct FooBar: View {

    @Environment(\.lineLimit) var lineLimit

    var body: some View {
        Text("Hello World!")
            .onAppear {
                print(lineLimit) // prints given environment value
            }
    }

}

TabBarController 实现中,我设置了三个带有根视图FooBar 的选项卡,它提供了一个带有根视图FooBar 的模态视图控制器。 FooBar 只在出现时从其EnvironmentValues 打印lineLimit 的值。我将lineLimit 设置为 3 以覆盖其默认值。选项卡组件打印 3,而呈现的视图打印 nil(这是默认值)。

我做错了什么,还是被禁止了?很奇怪,因为来自SwiftUI 框架的sheet() 确实按预期工作(尽管我不能使用这个API,因为我需要完全控制UIViewController 演示文稿才能应用自定义转换)。

【问题讨论】:

    标签: ios swift swiftui uikit


    【解决方案1】:

    SwiftUI 的 EnvironmentObjectsEnvironmentValues 应该仅传播到 SwiftUI 子视图。对于其他(跨框架/API)情况,我们必须手动执行此操作,例如

    struct TabBarController: UIViewControllerRepresentable {
        @Environment(\.lineLimit) var lineLimit                // << here !!
    
        typealias UIViewControllerType = UITabBarController
    
        func makeUIViewController(context: Context) -> UIViewControllerType {
            let uiViewController = UITabBarController()
            uiViewController.setViewControllers([
                UIHostingController(rootView: 
                    FooBar().environment(\.lineLimit, lineLimit)),   // << here !!
                UIHostingController(rootView: FooBar()),
                UIHostingController(rootView: FooBar())
            ], animated: false)
            return uiViewController
        }
    
        // ... other code
    }
    

    【讨论】:

    • 是的,我可以为 EnvironmentValues 做到这一点,但这不是一种可扩展的方式。此外,正如我上面提到的,来自SwiftUI 框架的sheet() API 确实将环境值传播到其呈现的工作表中。
    猜你喜欢
    • 2014-05-01
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多