在SwiftUI视图中实现委托

32

我正在尝试实现一项需要委托方法的功能(类似于NSUserActivity)。因此,我需要一个符合NSUserActivityDelegate(或其他类似委托)协议的UIViewController,处理和保留所有所需信息。我的问题是,我正在使用SwiftUI进行界面设计,因此没有使用UIViewControllers。那么,我该如何实现这个功能并仍然使用SwiftUI进行界面设计呢?我尝试过的方法:view1只是一个普通的SwiftUI View,可以通过NavigationLink呈现view2,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 View中实现这样的功能。


如果您的应用程序是一个 SwiftUI 应用程序 - 而且看起来确实是这样 - 那么您 必须 使用 UIViewControllerRepresentable。没有它?您将无法实现委托方法。现在,您可能会感到困惑 - UIHostingController 是如何反向操作的...将 SwiftUI 视图添加到您的 UIKit 项目中。这里(以及其他地方,包括 WWDC 视频)有相当不错的示例说明了如何在 SwiftUI 项目中使用 UIViewController。我的建议是:(1)在 UIKit 项目中首先让某些东西工作,然后(2)在 SwiftUI 应用程序中公开它 - 记住,UIViewcontrollerRepresentable 只是一个 SwiftUI View - user7014451
很抱歉,我已经更正了我的代码:view1链接到一个UIViewControllerRepresentable,以便向我的应用程序添加一个UIViewController来处理我的委托。由于我想在SwiftUI中进行UI设计,因此这个UIViewController会附加一个子vc(请参见代码),它是一个UIHostingController,以便在SwiftUI视图中呈现UI。我的问题是,我无法真正在我的UIViewController(委托处理程序)和我的SwiftUI View(view2)之间传递信息。 - l30c0d35
1
UIHostingController 仅在 UIKit 应用程序中使用。这是将 SwiftUI 的 View 带入 UIKit 的方法。基本上,您可以使用 UIViewControllerRepresentable(UIKit >> SwiftUI)或 UIHostingController(SwiftUI >> UIKit)。有关更多详细信息,请查看第 231 会话:集成 SwiftUI。 - user7014451
好的,我明白了。但是我如何在一个 UIViewController 上处理我的代理方法,而不使用它作为 UI,而是使用 view2(一个 Swift UI View)呢? - l30c0d35
我在我的SwiftUI项目中创建了三个 UIViewControllerRepresentable。MTKView,UIImagePickerController和UIActivityViewController。它们中的两个使用委托(前两个)。我真的不确定它们是否能帮助你,但我愿意尝试。图像选择器的想法是(a)展示它,(b)使用委托方法来获取所选图像或传递取消按钮被按下的信息,然后(c)将其解除显示。它与我的模型相关联 - 从beta 5开始现在称为“ObservableObject”,并在应用程序状态更新时更新各种SwiftUI视图。这有助于您吗? - user7014451
可能会。你可以尝试写一个答案并展示一些代码。即使你不确定它是否有帮助,因为你仍然可以更新答案。 - l30c0d35
1个回答

36

您需要创建一个符合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”,并更新数据实例变量。


问题在于:NavigationLink 的目标是 VCRepresentable,该 VCRepresentablemakeUIViewController(context :) 中返回 ImplementationVC 以供 UI 使用,这将要求我在我的 ImplementationVC 中进行 UI 设计(因此使用 UIKit)。 - l30c0d35
1
对于 SomeDelegate,我正在使用 NSUserActivityDelegate,但是不知何故无法访问 self.userActivity。当我使用 class VC: UIViewController, NSUserActivityDelegate { ... } 时,我可以访问它。对于 someDelegateFunction(data:),例如我也无法访问 updateUserActivityState(_ activity:) - l30c0d35
vc.delegate 代表什么?因为 UIViewController 没有成员变量 delegate。 - l30c0d35
2
很高兴你解决了问题!我会将“UIViewController”重命名为更通用的名称;视图控制器应该是委托所属的任何类型的视图控制器。例如,如果您想要监听tableview委托方法,您可以将视图控制器设置为“TableViewController”,或者将结构体设置为“UIViewRepresentable”,并使用“TableView”,然后在协调器中连接其委托。 - RPatel99
2
为了更好地理解Coordinator,这里有一个非常好的关于它的教程:https://www.hackingwithswift.com/books/ios-swiftui/using-coordinators-to-manage-swiftui-view-controllers - Skoua
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接