【问题标题】:SwiftUI - How to access UIHostingController from SwiftUISwiftUI - 如何从 SwiftUI 访问 UIHostingController
【发布时间】:2021-07-23 10:44:35
【问题描述】:

我有 SwiftUI 页面,它是从 UIKit 视图导航的。我想给这个页面设置一个标题,我正在做的是

// code of UIKit view
let controller = UIHostingController(rootView: SwiftUIView())
controller.title = "title"
MyNavigationManager.present(controller)

有没有办法可以在 SwiftUI 中访问主机控制器?

然后我可以编写如下代码 self.hostingController?.title = "title"

【问题讨论】:

  • 最后我选择了一个简单的方法,在宿主控制器中,将 self 传递给 SwiftUI rootView.hostingController = self

标签: swiftui uihostingcontroller


【解决方案1】:

这是一个可能方法的演示 - 使用外部配置包装类来保存到控制器的弱链接并将其注入到 SwiftUI 视图中(作为替代,也可以使其 ObservableObject 与其他全局属性和逻辑相结合)。

使用 Xcode 12.5 / iOS 14.5 测试

class Configuration {
    weak var hostingController: UIViewController?    // << wraps reference
}

struct SwiftUIView: View {
    let config: Configuration   // << reference here

    var body: some View {
        Button("Demo") {
            self.config.hostingController?.title = "New Title"
        }
    }
}

let configuration = ExtConfiguration()
let controller = UIHostingController(rootView: SwiftUIView(config: configuration))

// injects here, because `configuration` is a reference !!
configuration.hostingController = controller

controller.title = "title"
MyNavigationManager.present(controller)

【讨论】:

    【解决方案2】:

    我选择了一个不同的选项 - 子类 NSHostingController 以便它提供自己作为环境变量。

    struct SwiftUIView: View {
        @EnvironmentObject var host:HSHostWrapper
    
        var body: some View {
            Button("Dismiss") {
                host.controller?.dismiss(self)
            }
        }
    }
    
    let controller = HSHostingController(rootView: SwiftUIView())
    

    这是通过以下 HSHostingController 实现的(在 HSSwiftUI package 中可用)

    import Foundation
    import SwiftUI
    
    
    #if os(iOS) || os(tvOS)
        import UIKit
        public typealias ViewController = UIViewController
        public typealias HostingController = UIHostingController
    #elseif os(OSX)
        import AppKit
        public typealias ViewController = NSViewController
        public typealias HostingController = NSHostingController
    #endif
    
    public class HSHostWrapper:ObservableObject {
        public weak var controller:ViewController?
    }
    
    
    /// allows root view (and children) to access the hosting controller by adding
    /// @EnvironmentObject var host:HSHostWrapper
    /// then e.g. host.controller?.dismiss()
    public class HSHostingController<Content>:HostingController<ModifiedContent<Content,SwiftUI._EnvironmentKeyWritingModifier<HSHostWrapper?>>> where Content : View {
        
        public init(rootView:Content) {
            let container = HSHostWrapper()
            let modified = rootView.environmentObject(container) as! ModifiedContent<Content, _EnvironmentKeyWritingModifier<HSHostWrapper?>>
            super.init(rootView: modified)
            container.controller = self
        }
      
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-04-01
      • 2020-01-22
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-14
      • 2022-11-05
      相关资源
      最近更新 更多