简体   繁体   English

在 SwiftUI 视图中实现委托

[英]Implement delegates within SwiftUI Views

I am trying to implement a functionality that requires a delegate method (like NSUserActivity ).我正在尝试实现一个需要委托方法的功能(如NSUserActivity )。 Therefore I need a UIViewController that conforms to NSUserActivityDelegate (or similar other delegates), handles and hold all the required information.因此,我需要一个符合NSUserActivityDelegate (或类似的其他委托)的UIViewController ,处理并保存所有必需的信息。 My problem is that I am using SwiftUI for my interface and therefore I am not using UIViewControllers .我的问题是我的界面使用 SwiftUI,因此我没有使用UIViewControllers So how can I implement this functionality and still use SwiftUI for the UI.那么我怎样才能实现这个功能并且仍然使用 SwiftUI 作为 UI。 What I tried: view1 is just a normal SwiftUI View that can present (via NavigationLink ) view2 which is the view where in want to implement this functionality.我尝试过的: view1 只是一个普通的 SwiftUI View ,它可以(通过NavigationLink )呈现 view2,这是要实现此功能的视图。 So I tried instead of linking view1 and view2, linking view1 to a UIViewControllerRepresentable which then handles the implementation of this functionality and adds UIHostingController(rootView: view2) as a child view controller.因此,我尝试将 view1 链接到UIViewControllerRepresentable而不是链接 view1 和 view2,后者然后处理此功能的实现并将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)
    }
}

I am having trouble with transferring the data between my VC and my view2.我在 VC 和 view2 之间传输数据时遇到问题。 So I'm wondering if there is a better way to implement such a functionality within a SwiftUI View.所以我想知道是否有更好的方法在 SwiftUI 视图中实现这样的功能。

You need to create a view that conforms to UIViewControllerRepresentable and has a Coordinator that handles all of the delegate functionality.您需要创建一个符合UIViewControllerRepresentable的视图,并有一个处理所有委托功能的Coordinator

For example, with your example view controller and delegates:例如,使用您的示例视图控制器和委托:

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)
        }
    }
}

Usage:用法:

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)
            }
        }
    }
}

Note : I renamed VCRepresentable to SomeDelegateObserver to be more indicative of what it does: Its sole purpose is to wait for delegate functions to execute and then run the closures (ie foo in this example) you provide it.注意:我将VCRepresentable重命名为SomeDelegateObserver以更好地说明它的作用:它的唯一目的是等待委托函数执行,然后运行您提供的闭包(即本例中的foo )。 You can use this pattern to create as many functions as you need to "observe" whatever delegate functions you care about, and then execute code that can update the UI, your data model, etc. In my example, when SomeDelegate fires someDelegateFunction(data:) , the view will display "Excuted" and update the data instance variable.您可以使用此模式创建尽可能多的函数以“观察”您关心的任何委托函数,然后执行可以更新 UI、数据模型等的代码。在我的示例中,当SomeDelegate触发someDelegateFunction(data:) ,视图将显示“已执行”并更新数据实例变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM