我有一个UIKit应用程序,使用UIHostingController来显示SwiftUI视图.在这个视图中有一个按钮,我想用它导航到另一个视图控制器.How can I push a new viewController from inside this SwiftUI view?(或者更笼统地说:我如何从SwiftUI视图内部调用我的视图控制器中的函数?)

当然,我可以只在SwiftUI中导航视图,但我最想使用UIKit,以便在业务逻辑和UI之间有清晰的分离.


import UIKit
import SwiftUI

class MainViewController: UIViewController {

    var viewModel = ViewModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        addView()
    }
    
    func addView() {
            let testView = SwiftUIView(viewModel: viewModel)
            let controller = UIHostingController(rootView: testView)
            addChild(controller)
            controller.view.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(controller.view)
            controller.didMove(toParent: self)

            NSLayoutConstraint.activate([
                controller.view.widthAnchor.constraint(equalTo: view.widthAnchor),
                controller.view.heightAnchor.constraint(equalTo: view.heightAnchor),
                controller.view.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                controller.view.centerYAnchor.constraint(equalTo: view.centerYAnchor)
            ])
        }

    func navigate() { // how do I call this from inside SwiftUI testView view?
        let otherView = Text("test")
        let nextVc = UIHostingController(rootView: otherView)
        navigationController?.pushViewController(nextVc, animated: true)
    }
}

SwiftUI类似于:

import SwiftUI

struct SwiftUIView: View {
    
    @ObservedObject var viewModel: ViewModel
    
    var body: some View {
         Button {
                    // push new view controller
                } label: {
                    Text("go")
                }
    }
}

推荐答案

将MainView控制器设置为ObserveObject

将环境对象设置为testView

使用@EnvironmentObject var parent: MainViewController访问视图内的环境对象

class MainViewController: UIViewController, ObservableObject {

    var viewModel = ViewModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        addView()
    }
    
    func addView() {
            let testView = SwiftUIView(viewModel: viewModel)
            let controller = UIHostingController(rootView: testView.environmentObject(self))
            addChild(controller)
            controller.view.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(controller.view)
            controller.didMove(toParent: self)

            NSLayoutConstraint.activate([
                controller.view.widthAnchor.constraint(equalTo: view.widthAnchor),
                controller.view.heightAnchor.constraint(equalTo: view.heightAnchor),
                controller.view.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                controller.view.centerYAnchor.constraint(equalTo: view.centerYAnchor)
            ])
        }
}

struct SwiftUIView: View {
    @EnvironmentObject var parent: MainViewController
    var body: some View {
        Button {
            // push new view controller
            parent.navigationController?.pushViewController(<#T##viewController: UIViewController##UIViewController#>, animated: <#T##Bool#>)
        } label: {
            Text("go")
        }
    }
    
}

Ios相关问答推荐

更新@PersistableEnum时是否需要执行迁移块?

为什么Reaction-Native-Vision-Camera不能与闪光灯一起使用?

在滚动视图中固定页眉,但在页眉上方嵌入元素

创建方案时运行 pod install 时出错

如何解决错误 HE0004:无法在 Visual Studio 2022 中加载框架ContentDeliveryServices

使用按位|带有布尔操作数

在 Swift 中 @MainActor 似乎被 withCheckedContinuation 而不是其他异步调用继承是巧合吗?

SwiftUI:同时拖动父视图和子视图,但手指分开

通过 Rosetta 打开模拟器 xcode 14 以修复滚动

有哪些可靠的机制可以防止 CoreData CloudKit 中的数据重复?

将视图(例如 Text())不透明度设置为 0 或将背景设置为 Color.clear 会导致它不被绘制

Apple Push Service 证书不受信任

iOS 中是否有用于自定义振动的 API?

iOS 10 错误:UICollectionView 接收到具有不存在索引路径的单元格的布局属性

iOS 7 圆形框架按钮

Xcode / iOS模拟器:手动触发重大位置更改

自动布局:是什么创建了名为 UIView-Encapsulated-Layout-Width & Height 的约束?

使用 swift 将本地 html 加载到 UIWebView

从故事板导航到其他 Swift 1.2 文件时 Xcode 6.3 崩溃

Objective-C 将 NSDate 设置为当前 UTC