我发现SwiftUI方面特别缺少交互方面的某些功能。因此,我试图添加一个介于两个UIView之间的中间“不可见” UIViewController。
TL; DR:请参见下面的第1点。
例如,要确保视图可以接收UIDrop交互,或添加UIDrag交互,或实际上可能受其他软件影响的任何其他交互(例如从其他软件拖到我的iPad上)。 / p>
因此,我创建了一些有趣的代码,它们实际上只是包装了视图“ Content”,并在实际实例化视图时被调用。我想放弃Controller部分,但在方程式的iOS部分似乎不可能,只有macOS。嘘无论如何,我知道这些功能最终可能会添加到SwiftUI中,因此该桥的明显目标是尽可能透明,因此只要有适当的方法添加到SwiftUI中,我就可以将其删除。
不管您信不信,它通常都能正常工作!但是这里有一个顽固的问题和一个错误,也许有人实际上做了类似的事情,并且实际上可以帮助我解决问题。也许我的代码可以作为一个很好的起点来帮助其他人。
(SwiftUI 11.0 beta 5)
(错误和主要问题)似乎帧大小没有传播。因此,我班的父类实际上必须对.frame(width: something, height: something)
进行硬编码,否则我的视图的大小将不合适。这是有道理的,因为我实际上没有传播这些值也不从Content检索它们。我尝试拥抱尺寸,但未发送相框尺寸。我应该在哪里以及如何全面获得该价值。我的代码的目标是使这座桥对SwiftUI,开发人员和最终用户尽可能地精益,高效和不可见。
(Nitpick)我发现实际上没有调用viewWillAppear
,viewDidLoad
和其他加载时间操作。例如,在观看时不会调用viewWillAppear
。如果我更深入地导航并返回,则将调用viewWillAppear
,但不是第一次显示。因此,我诉诸于创建一个临时的“初始化”变量。我在做什么错(如果有的话)?
也许我也忘记了在类和结构之间传输其他数据。例如,UIViewController实际上使对象的背景为白色。它可能是透明的,但对我而言并不重要(我想您可以添加self.view.backgroundColor = .clear
)。如果您想到改进,我将非常高兴知道它!
import SwiftUI
/// Creates a SwiftUI to UIKit to SwiftUI bridge, where a lambda is called on viewWillAppear
struct UIKitBridgeView<Content>: View where Content : View {
var content: () -> Content
var onViewWillAppear: (UIView)->Void
init(onViewWillAppear: @escaping (UIView)->Void, _ content: @escaping () -> Content) {
self.content = content
self.onViewWillAppear = onViewWillAppear
}
class Coordinator: NSObject {
}
/// This is the class in UIKit that can host a SwiftUI "Content" type.
class HostingController: UIHostingController<Content> {
var onViewWillAppear: ((UIView)->Void)?
var initialized: Bool = false
init(_ content: () -> Content) {
super.init(rootView: content())
self.onViewWillAppear = nil
}
init(_ content: () -> Content, _ onViewWillAppear: @escaping (UIView)->Void) {
super.init(rootView: content())
self.onViewWillAppear = onViewWillAppear
}
@objc required dynamic init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.onViewWillAppear = nil
}
func update(context: UIViewControllerRepresentableContext<ViewControllerRepresentable>) {
if !initialized {
initialized = true
if let onViewWillAppear = self.onViewWillAppear {
onViewWillAppear(self.view)
}
// self.view.setContentHuggingPriority(.defaultHigh, for: .vertical) doesn't seem to do anything...
// self.view.setContentHuggingPriority(.defaultHigh, for: .horizontal)
}
}
}
/// This is the struct in SwiftUI that can host a UIKit's ViewController
struct ViewControllerRepresentable : UIViewControllerRepresentable {
let content: () -> Content
var onViewWillAppear: ((UIView)->Void)?
init(_ content: @escaping () -> Content) {
self.content = content
self.onViewWillAppear = nil
}
init(_ content: @escaping () -> Content, _ onViewWillAppear: @escaping (UIView)->Void) {
self.content = content
self.onViewWillAppear = onViewWillAppear
}
func makeUIViewController(context: Context) -> HostingController {
self.onViewWillAppear != nil ?
HostingController(self.content, self.onViewWillAppear!) :
HostingController(self.content)
}
func updateUIViewController(_ hostingController: HostingController, context: Context) {
hostingController.update(context: context)
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
}
var body: some View {
ViewControllerRepresentable(self.content, self.onViewWillAppear)
}
}
对于第1点不完整的示例:
UIKitBridgeView(onViewWillAppear: { (view) in
if let delegate = self.appState.dragInteractionDelegate {
view.addInteraction(self.createDraggable(delegate))
}
}) {
Spacer() // Insert what you want here
}.frame(width: 50, height: 50)
.frame(width, height)
真的让我很烦!