0

我的应用程序是UIKit&的混合体SwiftUI。我有一个用例,用户可能需要Button从 a 中点击 aSwiftUI.View但推送到 aUIViewController或 another UIHostingController

我的项目使用Storyboard.

我正在使用UINavigationController& UITabBarController

我正在研究两种情况。

1.) 从我在主屏幕上首次启动时,我可以点击一个按钮,在它的操作中我有:

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

这按预期工作。

2.) 我点击另一个选项卡,它默认为我的SwiftUIRootView,它托管在UIHostingController我在我的Storyboard. 在这里,如果我点击一个按钮来触发推送,它不会推送。我只看到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.
4

1 回答 1

0

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

假设您的应用程序有两个选项卡。我会先SwiftUI.View输入UIHostingController,然后再输入UINavigationController。在SwiftUI.View我会放置闭包let onTap: () -> Void,每当您需要推送 nextUIHostingControllerUIViewControllerto时都会调用它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
    }
}
于 2021-07-19T20:22:44.983 回答