SwiftUI 在 UIViewController 中调用委托

SwiftUI calling delegate in UIViewController

这是我第一次使用 SwiftUI,我已经搜索过这个问题但没有找到任何有效的解决方案,所以我将不胜感激所有能得到的帮助。

我有一个 UIViewController,我在其中通过 UIHostingController 呈现一个 SwiftUI 视图。我想要实现的是,当我在 SwiftUI 视图中按下按钮时,该操作将触发 UIViewController 中的委托,或者,触发 UIViewController 中的函数,然后从该函数中触发触发委托。

class MyViewController: UIViewController {

public var delegate: MyViewControllerDelegate?
let facialView = UIHostingController(rootView: FacialTutorial())

override func viewWillAppear(_ animated: Bool) {

addChild(facialView)
view.addSubview(facialView.view)
setupConstraints()

}

extension MyViewController {

@objc private func buttonPressed() {

delegate?.buttonPressed()

}

}


}

并且在我的 SwiftUI 视图中 FacialTutorial

struct FacialTutorial: View {

var body: some View {

        VStack() {
          Button {
              // I want to call delegate?.buttonPressed() action here
          } label: {
              Text("Press button")
          }
        
      }

}


}

编辑

好吧,说得更清楚一些,我的 ViewController 为许多情况配置了不同的页面。所以在实践中,我不会从 viewWillAppear 启动 SwiftUI 视图。我就是这样做的

public var delegate: MyViewControllerDelegate?
let facialView = UIHostingController(rootView: FacialTutorial())


override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    addChild(facialView)
    configureSubviews()
}



private func configureForInstructionMode() {

  view.addSubview(facialUIView.view)
  setupConstraints()
}

我必须这样做,因为我需要根据我要配置的模式来配置不同的视图。当我在 viewDidLoad 或 viewWillAppear 中声明 facialView 时,我无法访问 configureForInstructionMode() 中的实例,或者它的值为 nil..

您只需将对 MyViewController 实例的引用传递给 MyUIView(可能应该是 MyView,因为它不是 UIView 的子类) 通过它的初始化器。您可以使用委托模式,也可以传递一个闭包,然后从闭包中调用委托方法。第二种方式更“迅捷”。

(我已将代码移至 viewDidLoad,因为如果您在 viewWillAppear 中拥有它,则如果视图控制器出现并消失并再次出现,则视图可能会被添加多次)

class MyViewController: UIViewController {

    public var delegate: MyViewControllerDelegate? {
        
    weak var myView: UIHostingController<MyUIView>!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let myView = UIHostingController(rootView: MyUIView(buttonHandler: { [weak self] in
                self?.delegate?.buttonPressed()
            }))
        self.myView = myView
        view.addSubview(myView.view)
        setupConstraints()
    }
}

然后,在您的 SwiftUI 视图中,您可以声明一个 属性 来保存闭包并在您的按钮中调用该闭包

struct MyUIView: View {
    
    var buttonHandler: (()->Void)?
    
    var body: some View {
        VStack() {
            Button {
                buttonHandler?()
            } label: {
                Text("Press button")
            }
            
        }
    }
}