繁体   English   中英

从 SwiftUI 推送到 UIViewController

[英]Push to UIViewController from SwiftUI

我的应用程序是UIKitSwiftUI的混合SwiftUI 我有一个用例,用户可能需要点击SwiftUI.ViewButton但推送到UIViewController或另一个UIHostingController

我的项目使用Storyboard

我正在使用UINavigationControllerUITabBarController

我正在考虑两种情况。

1.) 从我在主屏幕上的初始启动开始,我可以点击一个按钮,并在其操作中:

let vc = UIHostingController(rootView: RootView())
self.navigationController?.pushViewController(vc, animated: true)

这按预期工作。

2.) 我点击一个不同的选项卡,它默认为我的SwiftUI RootView,它托管在我在Storyboard使用的自定义UIHostingController中。 在这里,如果我点击一个按钮来触发推送,它不会推送。 我只看到我正在更新的View

我也在使用自定义UINavigationController 从我的Storyboard ,选项卡关系转到自定义UINavigationController & 然后它的根是适当的UIViewController 在一种情况下,虽然它是我的自定义UIHostingController因此我可以最初从选项卡选择加载SwiftUI视图。

这是我尝试从我的 SwiftUI 视图处理推送到视图控制器的操作:

final class AppData: ObservableObject {
    weak var window: UIWindow? // Will be nil in SwiftUI previewers

    init(window: UIWindow? = nil) {
        self.window = window
    }
    
    public func pushViewController(_ viewController: UIViewController, animated: Bool = true) {
        let nvc = window?.rootViewController?.children.first?.children.first as? UINavigationController
        nvc?.pushViewController(viewController, animated: animated)
    }
}

// This is what is triggered from the Button action.
func optionSelected(option: String) {
    if let optionId = Common.getIDByOption(option: option) {
        let vc = UIHostingController(rootView: RootView())                
        appData.pushViewController(vc, animated: true)
    }
}

怎么了:

  • 我确实看到数据发生了变化,但它们都在我已经使用的同一个视图中。
  • 我需要推送到新的UIHostingController

如果您以UITabBarControllerUINavigationController处理导航的方式混合UIKitSwiftUI 我建议你剪掉NavigationViewNavigationLink 背后的原因很简单。 SwiftUI.View将在每次切换到选项卡时重新创建。 因此,您将从头开始。 您可以四处走动,但在这种情况下,使用UINavigationController会更容易。

假设您的应用程序有两个选项卡。 我会把SwiftUI.ViewUIHostingController ,然后在UINavigationController SwiftUI.View我将关闭let onTap: () -> Void每当您需要将下一个UIHostingControllerUIViewController推送到UINavigationController时都会调用它。

例子

//: A UIKit based Playground for presenting user interface

import UIKit
import SwiftUI
import PlaygroundSupport

final class MainViewController: UITabBarController {
    let firstTab: UINavigationController = {
        let navigationController = UINavigationController()
        navigationController.tabBarItem = UITabBarItem(title: "First", image: nil, tag: 1)
        return navigationController
    }()

    let secondTab: UINavigationController = {
        let navigationController = UINavigationController()
        navigationController.tabBarItem = UITabBarItem(title: "Second", image: nil, tag: 1)
        return navigationController
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setUpFirstTab()
        setUpSecondTab()
        viewControllers = [firstTab, secondTab]
    }

    func setUpFirstTab() {
        let firstView = FirstView { number in
            let secondViewHostingController = UIHostingController(rootView: SecondView(number: number))
            self.firstTab.pushViewController(secondViewHostingController, animated: true)
        }
        let firstViewHostingController = UIHostingController(rootView: firstView)
        firstTab.tabBarItem = UITabBarItem(title: "First", image: nil, tag: 1)
        firstTab.viewControllers = [firstViewHostingController]
    }

    func setUpSecondTab() {
        secondTab.tabBarItem = UITabBarItem(title: "Second", image: nil, tag: 2)
        secondTab.viewControllers = [FirstViewController()]
    }
}

// Views for the first tab
struct FirstView: View {
    let onTap: (Int) -> Void
    @State var number: Int = 0
    var body: some View {
        VStack {
            Stepper("Number \(number)", value: $number)
            Button {
                onTap(number)
            } label: {
                Text("Go to the next view")
            }
        }
    }
}

struct SecondView: View {
    let number: Int
    var body: some View {
        Text("Final view with number \(number)")
    }
}

// Views controllers for the second tab
final class FirstViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let button: UIButton = UIButton(type: .roundedRect, primaryAction: UIAction(title: "show next view controller") { _ in
            self.navigationController?.pushViewController(SecondViewController(), animated: true)
        })
        button.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(button)
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        ])
    }
}

final class SecondViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemPink
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM