是否可以将 ViewController 分配给 SwiftUI 视图?

Is it possible to assign a ViewController to a SwiftUI view?

我正在使用 SwiftUI 应用程序协议构建 SwiftUI 应用程序。

我需要访问一些 UIKIt 函数,尤其是控制 NavigationView 的函数,如下所示:.

显然,要做到这一点,我需要将我的 SwiftUI 视图与 ViewController 绑定。

我已尝试执行以下操作:

ContentView.swift

struct ContentView: View {
    
    var body: some View {
        ZStack {
            ContentViewIntegratedController() // <- here
            NavigationView{
                ScrollView {
                    Text("Content View")
                        .navigationTitle("Content View")

                }
            }
        }
    }
}

class ContentViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

struct ContentViewIntegratedController: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> some UIViewController {
        return ContentViewController()
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType,
                                context: UIViewControllerRepresentableContext<ContentViewIntegratedController>) {}
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


但是调用 ContentViewIntegratedContoller(第 5 行)似乎创建了一个新的预览而不是修改现有的。

有没有集成一个ViewController来修改SwiftUI视图?

我不想做的事:

有没有其他方法可以在不向我的 SwiftUI 视图添加 ViewController 的情况下访问这些功能?

TIA。

纯 SwiftUI 无法直接检测 largeinline 显示模式之间的变化。但是,使用 SwiftUI-Introspect,你可以下降到 UIKit 来解决这个问题。

我通过获取大标题的视图并检测 alpha 属性 何时更改来解决此问题。这在标题从 large 变为 inline 或 vice-versa.

的确切时刻发生变化

代码:

struct ContentView: View {
    @State private var observer: NSKeyValueObservation?
    @State private var title: String = "Large Title"

    var body: some View {
        NavigationView {
            ScrollView {
                Text("Hello world!")
            }
            .navigationTitle(title)
        }
        .introspectNavigationController { nav in
            let largeTitleView = nav.navigationBar.subviews.first { view in
                String(describing: type(of: view)) == "_UINavigationBarLargeTitleView"
            }
            observer = largeTitleView?.observe(\.alpha) { view, change in
                let isLarge = view.alpha == 1
                title = isLarge ? "Large Title" : "Inline title"
            }
        }
    }
}

结果:

    struct ContentView: View {
    var body: some View {
        ContentViewIntegratedController(view: YourView())
            .ignoresSafeArea()
    }
    }




--------------------------------------------------------------
    struct YourView: View {
    var body: some View {
        ScrollView{
        Text("Hello, World!")
        }
    }}
------------------------------------------------------
    import Foundation
    import SwiftUI

    struct ContentViewIntegratedController :UIViewControllerRepresentable{
    
    var view: YourView
    
    init(view:YourView) {
        self.view = view
    }
    
    func makeUIViewController(context: Context) -> UINavigationController{
        
        let childView = UIHostingController(rootView: view)
        let controller =     UINavigationController(rootViewController:childView)
        let appearance = UINavigationBarAppearance()
        let searchController = UISearchController()
        
        
        searchController.searchBar.barStyle = .black
        
        appearance.backgroundColor = UIColor(Color(.red))
        appearance.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
        appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
        
        
        controller.navigationBar.topItem?.compactAppearance = appearance
        controller.navigationBar.topItem?.scrollEdgeAppearance = appearance
        controller.navigationBar.topItem?.standardAppearance = appearance
        

        controller.navigationBar.topItem?.title = "navigation bar"
        controller.navigationBar.prefersLargeTitles = true
        
        searchController.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "Rechercher...", attributes: [NSAttributedString.Key.foregroundColor: UIColor.white])
        searchController.searchBar.setValue("Annuler", forKey: "cancelButtonText")
        
        
        searchController.searchBar.showsBookmarkButton = true
        searchController.searchBar.searchTextField.leftView?.tintColor = .white
        
        let sfConfiguration = UIImage.SymbolConfiguration(pointSize: 30)
        let barCodeIcon = UIImage(systemName: "barcode.viewfinder")?.withTintColor(.white, renderingMode: .alwaysOriginal).withConfiguration(sfConfiguration)
    

        searchController.searchBar.setImage(barCodeIcon, for: .bookmark, state:.normal)
        searchController.obscuresBackgroundDuringPresentation = false
  

        let attributes = [NSAttributedString.Key.foregroundColor : UIColor.white]
        UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).setTitleTextAttributes(attributes, for: .normal)
       
        controller.navigationBar.topItem?.hidesSearchBarWhenScrolling = false
        controller.navigationBar.topItem?.searchController = searchController
        
        return controller
        
    }
    
    
    func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {
        
    }}