how to push ViewController from inside UIHostingController's SwiftUI view using pushViewController?

huangapple go评论73阅读模式
英文:

how to push ViewController from inside UIHostingController's SwiftUI view using pushViewController?

问题

我有一个使用UIHostingController来显示SwiftUI视图的UiKit应用程序。在这个视图中有一个按钮,我想要使用它来导航到另一个ViewController。我如何可以从这个SwiftUI视图内部推出一个新的ViewController?(或更一般地说:我如何可以从SwiftUI视图内部调用ViewController中的函数?)

当然,我可以在SwiftUI内部使用NavigationView,但我想要尽可能多地使用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() { // 我如何可以从SwiftUI的testView视图内部调用这个函数?
        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 {
            // 推出新的视图控制器
            // 你可以在这里调用MainViewController的navigate()函数
        } label: {
            Text("go")
        }
    }
}
英文:

I have a UiKit app using a UIHostingController to show a SwiftUI view. In this view there is a button, which I want to use to navigate to another ViewController. How can I push a new viewController from inside this SwiftUI view? (or more generally: how can I call a function from my ViewController from inside the SwiftUI view?)

Of course I could just NavigationView inside SwiftUI, but I want to do most with UiKit, in order to have clean separation between business logic and 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)
    }
}

with the SwiftUI being something like:

import SwiftUI

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

答案1

得分: 1

使你的MainViewController成为ObservableObject

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 {
            // 推入新的视图控制器
            parent.navigationController?.pushViewController(<#T##viewController: UIViewController##UIViewController#>, animated: <#T##Bool#>)
        } label: {
            Text("go")
        }
    }
}
英文:

Make your MainViewController as ObservableObject

Set environment object on testView

Access your environment object inside your view using @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(&lt;#T##viewController: UIViewController##UIViewController#&gt;, animated: &lt;#T##Bool#&gt;)
        } label: {
            Text(&quot;go&quot;)
        }
    }
    
}

答案2

得分: 0

调用此函数在你的按钮点击事件上。尽量使这个函数全局可用,这样你可以从任何SwiftUI视图中访问它。

func navigateToViewController(view: View)
{
    let newVC = UIHostingController(rootView: view)
    newVC.modalPresentationStyle = .overCurrentContext
    let transition = CATransition()
    transition.duration = 0.3
    transition.type = CATransitionType.push
    transition.subtype = CATransitionSubtype.fromRight
    transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    UIApplication.shared.windows[0].rootViewController!.view.window!.layer.add(transition, forKey: kCATransition)
    UIApplication.shared.windows[0].rootViewController!.present(newVC, animated: false, completion: nil)
}
英文:

call this function on your button-click event. try to make this function global so you can access it from every swiftUI View.

func navigateToViewController(view : any View)
{
    let newVC = UIHostingController(rootView: view)
    newVC.modalPresentationStyle = .overCurrentContext
    let transition = CATransition()
    transition.duration = 0.3
    transition.type = CATransitionType.push
    transition.subtype = CATransitionSubtype.fromRight
    transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    UIApplication.shared.windows[0].rootViewController!.view.window!.layer.add(transition, forKey: kCATransition)
    UIApplication.shared.windows[0].rootViewController!.present(newVC, animated: false, completion: nil)
}

huangapple
  • 本文由 发表于 2023年3月3日 21:23:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/75627630.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定