swiftui - 从 UIViewControllerRepresentable 对象访问 @Environment 对象

标签 swiftui environmentobject uiviewcontrollerrepresentable

我使用这种方法将相机与 swiftUI 相结合: https://medium.com/@gaspard.rosay/create-a-camera-app-with-swiftui-60876fcb9118

UIViewControllerRepresentable 由 PageFourView 类实现。 PageFourView是父View的TabView之一。我有一个 @EnvironmentObject 从 SceneDelegate 传递到父 View ,然后传递到 PageFourView。但是,当我尝试从 PageFourView 的 makeUIViewController 方法访问 @EnvironmentObject 时,出现错误:

Fatal error: No ObservableObject of type Data found. A View.environmentObject(_:) for Data may be missing as an ancestor of this view

... 即使我可以从 context.environment 中看到 @Environment 对象。这是我的代码:

import UIKit
import SwiftUI
import Combine


final class PageFourView: UIViewController, UIViewControllerRepresentable {
    
    public typealias UIViewControllerType = PageFourView
    
    @EnvironmentObject var data: Data
    
    var previewView: UIView!
    
    override func viewDidLoad() {
        
        previewView = UIView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height))
        
        previewView.contentMode = UIView.ContentMode.scaleAspectFit
        view.addSubview(previewView)
        
    }
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<PageFourView>) -> PageFourView {
        print(context.environment)
        print(self.data.Name)
        return PageFourView()
    }

    func updateUIViewController(_ uiViewController: PageFourView, context: UIViewControllerRepresentableContext<PageFourView>) {
    }
}

struct PageFourView_Previews: PreviewProvider {
    @State static var data = Data()
    static var previews: some View {
        PageFourView().environmentObject(self.data)
    }
}

这是调用 PageFourView 的父 View :


import SwiftUI

struct AppView: View {
    
    @EnvironmentObject var data: Data
    
    var body: some View {
        TabView {
            PageOneView().environmentObject(data)
                .tabItem {
                    Text("PageOne")
                }

            PageTwoView().environmentObject(data)
                .tabItem {
                    Text("PageTwo")
                }
            PageThreeView().environmentObject(data)
            .tabItem {
                Text("PageThree")
            }
            PageFourView().environmentObject(data)
            .tabItem {
                Text("PageFour")
            }
            
            
        }
    }
}

struct AppView_Previews: PreviewProvider {
    
    @State static var data = Data()
    static var previews: some View {
        AppView().environmentObject(self.data)
    }
}
final class CameraViewController: UIViewController {
    let cameraController = CameraController()
    var previewView: UIView!

    override func viewDidLoad() {

        previewView = UIView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height))
        previewView.contentMode = UIView.ContentMode.scaleAspectFit
        view.addSubview(previewView)

        cameraController.prepare {(error) in
            if let error = error {
                print(error)
            }

            try? self.cameraController.displayPreview(on: self.previewView)
        }

    }
}


extension CameraViewController : UIViewControllerRepresentable{
    public typealias UIViewControllerType = CameraViewController

    public func makeUIViewController(context: UIViewControllerRepresentableContext<CameraViewController>) -> CameraViewController {
        return CameraViewController()
    }

    public func updateUIViewController(_ uiViewController: CameraViewController, context: UIViewControllerRepresentableContext<CameraViewController>) {
    }
}

最佳答案

并且 UIViewRepresentableUIViewControllerRepresentable 是一个 View 并且必须是一个结构

在描述的情况下,不需要可表示的 Controller ,因为您使用 View 进行操作,因此这里是更正后的代码:

struct PageFourView: UIViewRepresentable {
    @EnvironmentObject var data: Data

    func makeUIView(context: Context) -> UIView {
        let view = UIView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.size.width, 
                          height: UIScreen.main.bounds.size.height))
        view.contentMode = UIView.ContentMode.scaleAspectFit

        print(context.environment)
        print(self.data.Name)
        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {
    }
}

顺便说一句,您不需要将 .environmentObject 传递给同一 View 层次结构中的 subview ,仅适用于新层次结构,例如工作表,因此您可以使用如下简化代码

var body: some View {
    TabView {
        PageOneView()
            .tabItem {
                Text("PageOne")
            }
        PageTwoView()
            .tabItem {
                Text("PageTwo")
            }
        PageThreeView()
        .tabItem {
            Text("PageThree")
        }
        PageFourView()
        .tabItem {
            Text("PageFour")
        }
    }
}

更新:对于 CameraViewController 只需将其包装如下

struct CameraView: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> CameraViewController {
        CameraViewController()
    }

    func updateUIViewController(_ uiViewController: CameraViewController, context: Context) {
    }
}

关于swiftui - 从 UIViewControllerRepresentable 对象访问 @Environment 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62824167/

相关文章:

ios - SceneKit – 在 SwiftUI 中渲染时相机看不到模型

ios - 实现 UserDefaults 时遇到问题

ios - 如何使用从类函数编辑环境对象?

ios - 当我的基于 SwiftUI 的应用程序以横向模式启动时,导航栏上的背景颜色未设置

swift - SwiftUI的 ".disabled"修饰符的变化可以动画吗?

SwiftUI 如何将全局变量传递给非 View 类

swiftui - @EnvironmentObject 和 @ObservedObject 有什么区别?

objective-c - SwiftUI 协调器 : method can not be marked @objc

swift - SwiftUI 下拉刷新数据