在 SwiftUI 视图中实现委托
Implement delegates within SwiftUI Views
我正在尝试实现需要委托方法的功能(如 NSUserActivity
)。因此,我需要一个符合 NSUserActivityDelegate
(或类似的其他代表)的 UIViewController
,处理并保存所有必需的信息。我的问题是我的界面使用 SwiftUI,因此我没有使用 UIViewControllers
。那么我怎样才能实现这个功能并仍然使用 SwiftUI 作为 UI。我尝试了什么:view1 只是一个普通的 SwiftUIView
,它可以呈现(通过 NavigationLink
)view2,它是想要实现此功能的视图。所以我尝试不链接 view1 和 view2,而是将 view1 链接到 UIViewControllerRepresentable
,然后处理此功能的实现并将 UIHostingController(rootView: view2)
添加为子视图控制器。
struct view1: View {
var body: some View {
NavigationLink(destination: VCRepresentable()) {
Text("Some Label")
}
}
}
struct view2: View {
var body: some View {
Text("Hello World!")
}
}
struct VCRepresentable: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
return implementationVC()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) { }
}
class implementationVC: UIViewController, SomeDelegate for functionality {
// does implementation stuff in delegate methods
...
override func viewDidLoad() {
super.viewDidLoad()
attachChild(UIHostingController(rootView: view2()))
}
private func attachChild(_ viewController: UIViewController) {
addChild(viewController)
if let subview = viewController.view {
subview.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(subview)
subview.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
subview.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
subview.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
subview.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
viewController.didMove(toParent: self)
}
}
我在 VC 和 view2 之间传输数据时遇到问题。所以我想知道是否有更好的方法在 SwiftUI 视图中实现这样的功能。
您需要创建一个符合 UIViewControllerRepresentable
并具有处理所有委托功能的 Coordinator
的视图。
例如,对于您的示例视图控制器和委托:
struct SomeDelegateObserver: UIViewControllerRepresentable {
let vc = SomeViewController()
var foo: (Data) -> Void
func makeUIViewController(context: Context) -> SomeViewController {
return vc
}
func updateUIViewController(_ uiViewController: SomeViewController, context: Context) { }
func makeCoordinator() -> Coordinator {
Coordinator(vc: vc, foo: foo)
}
class Coordinator: NSObject, SomeDelegate {
var foo: (Data) -> Void
init(vc: SomeViewController, foo: @escaping (Data) -> Void) {
self.foo = foo
super.init()
vc.delegate = self
}
func someDelegateFunction(data: Data) {
foo(data)
}
}
}
用法:
struct ContentView: View {
var dataModel: DataModel
var body: some View {
NavigationLink(destination: CustomView(numberFromPreviousView: 10)) {
Text("Go to VCRepresentable")
}
}
}
struct CustomView: View {
@State var instanceData1: String = ""
@State var instanceData2: Data?
var numberFromPreviousView: Int // example of data passed from the previous view to this view, the one that can react to the delegate's functions
var body: some View {
ZStack {
SomeDelegateObserver { data in
print("Some delegate function was executed.")
self.instanceData1 = "Executed!"
self.instanceData2 = data
}
VStack {
Text("This is the UI")
Text("That, in UIKit, you would have in the UIViewController")
Text("That conforms to whatever delegate")
Text("SomeDelegateObserver is observing.")
Spacer()
Text(instanceData1)
}
}
}
}
注意:我将VCRepresentable
重命名为SomeDelegateObserver
以更能说明它的作用:它的唯一目的是等待委托函数执行然后 运行 您提供的闭包(即本例中的 foo
)。您可以使用此模式创建尽可能多的函数来“观察”您关心的任何委托函数,然后执行可以更新 UI、您的数据模型等的代码。在我的示例中,当 SomeDelegate
触发 someDelegateFunction(data:)
,视图将显示“Excuted”并更新数据实例变量。
我正在尝试实现需要委托方法的功能(如 NSUserActivity
)。因此,我需要一个符合 NSUserActivityDelegate
(或类似的其他代表)的 UIViewController
,处理并保存所有必需的信息。我的问题是我的界面使用 SwiftUI,因此我没有使用 UIViewControllers
。那么我怎样才能实现这个功能并仍然使用 SwiftUI 作为 UI。我尝试了什么:view1 只是一个普通的 SwiftUIView
,它可以呈现(通过 NavigationLink
)view2,它是想要实现此功能的视图。所以我尝试不链接 view1 和 view2,而是将 view1 链接到 UIViewControllerRepresentable
,然后处理此功能的实现并将 UIHostingController(rootView: view2)
添加为子视图控制器。
struct view1: View {
var body: some View {
NavigationLink(destination: VCRepresentable()) {
Text("Some Label")
}
}
}
struct view2: View {
var body: some View {
Text("Hello World!")
}
}
struct VCRepresentable: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
return implementationVC()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) { }
}
class implementationVC: UIViewController, SomeDelegate for functionality {
// does implementation stuff in delegate methods
...
override func viewDidLoad() {
super.viewDidLoad()
attachChild(UIHostingController(rootView: view2()))
}
private func attachChild(_ viewController: UIViewController) {
addChild(viewController)
if let subview = viewController.view {
subview.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(subview)
subview.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
subview.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
subview.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
subview.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
viewController.didMove(toParent: self)
}
}
我在 VC 和 view2 之间传输数据时遇到问题。所以我想知道是否有更好的方法在 SwiftUI 视图中实现这样的功能。
您需要创建一个符合 UIViewControllerRepresentable
并具有处理所有委托功能的 Coordinator
的视图。
例如,对于您的示例视图控制器和委托:
struct SomeDelegateObserver: UIViewControllerRepresentable {
let vc = SomeViewController()
var foo: (Data) -> Void
func makeUIViewController(context: Context) -> SomeViewController {
return vc
}
func updateUIViewController(_ uiViewController: SomeViewController, context: Context) { }
func makeCoordinator() -> Coordinator {
Coordinator(vc: vc, foo: foo)
}
class Coordinator: NSObject, SomeDelegate {
var foo: (Data) -> Void
init(vc: SomeViewController, foo: @escaping (Data) -> Void) {
self.foo = foo
super.init()
vc.delegate = self
}
func someDelegateFunction(data: Data) {
foo(data)
}
}
}
用法:
struct ContentView: View {
var dataModel: DataModel
var body: some View {
NavigationLink(destination: CustomView(numberFromPreviousView: 10)) {
Text("Go to VCRepresentable")
}
}
}
struct CustomView: View {
@State var instanceData1: String = ""
@State var instanceData2: Data?
var numberFromPreviousView: Int // example of data passed from the previous view to this view, the one that can react to the delegate's functions
var body: some View {
ZStack {
SomeDelegateObserver { data in
print("Some delegate function was executed.")
self.instanceData1 = "Executed!"
self.instanceData2 = data
}
VStack {
Text("This is the UI")
Text("That, in UIKit, you would have in the UIViewController")
Text("That conforms to whatever delegate")
Text("SomeDelegateObserver is observing.")
Spacer()
Text(instanceData1)
}
}
}
}
注意:我将VCRepresentable
重命名为SomeDelegateObserver
以更能说明它的作用:它的唯一目的是等待委托函数执行然后 运行 您提供的闭包(即本例中的 foo
)。您可以使用此模式创建尽可能多的函数来“观察”您关心的任何委托函数,然后执行可以更新 UI、您的数据模型等的代码。在我的示例中,当 SomeDelegate
触发 someDelegateFunction(data:)
,视图将显示“Excuted”并更新数据实例变量。