SwiftUI - 如何从 SwiftUI 访问 UIHostingController
SwiftUI - How to access UIHostingController from SwiftUI
我有 SwiftUI 页面,它是从 UIKit 视图导航的。我想为这个页面设置一个标题,我正在做的是
// code of UIKit view
let controller = UIHostingController(rootView: SwiftUIView())
controller.title = "title"
MyNavigationManager.present(controller)
有什么方法可以访问 SwiftUI 中的托管控制器?
然后我可以写这样的代码
self.hostingController?.title = "title"
这是一个可能方法的演示 - 使用外部配置包装器 class 将弱 link 保存到控制器并将其注入 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)
我选择了一个不同的选项 - 将 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")
}
}
我有 SwiftUI 页面,它是从 UIKit 视图导航的。我想为这个页面设置一个标题,我正在做的是
// code of UIKit view
let controller = UIHostingController(rootView: SwiftUIView())
controller.title = "title"
MyNavigationManager.present(controller)
有什么方法可以访问 SwiftUI 中的托管控制器?
然后我可以写这样的代码
self.hostingController?.title = "title"
这是一个可能方法的演示 - 使用外部配置包装器 class 将弱 link 保存到控制器并将其注入 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)
我选择了一个不同的选项 - 将 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")
}
}