通过 Swift 泛型初始化 SwiftUI 视图
Posted
技术标签:
【中文标题】通过 Swift 泛型初始化 SwiftUI 视图【英文标题】:Initialising a SwiftUI View via a Swift generic 【发布时间】:2021-04-29 09:11:17 【问题描述】:我正在将 Pull To Refresh 添加到基于 SwiftUI 的应用程序中。为此,我不得不退回到 UIKit。由于我想跨多个表和数据模型(使用共享协议)使用 Pull To Refresh,因此我想使用泛型。
我传入了我的dataModel的类型,我还想传入我想在scrollView中实例化的SwiftUI View的类型。
但是,当我添加我声明支持协议“视图”的通用类型 V 时,我在代码尝试实例化视图时遇到编译错误。
类型“V”没有成员“init”
如果我放弃通用类型“V”,而是硬编码一个特定的 SwiftUI 视图类型来实例化,比如 DataView,这一切都很好 - 但这并没有给我所需的视图类型的灵活性。
请问我该如何解决这个编译错误?
import SwiftUI
struct GenericRefreshView<T, V>: UIViewRepresentable where T:ObservableObject, T:dataModel, V: View
@EnvironmentObject var dataModel: T
func makeCoordinator() -> Coordinator
Coordinator(self, regs: dataModel)
let size: CGSize
func makeUIView(context: Context) -> UIScrollView
let scrollView = UIScrollView()
scrollView.refreshControl = UIRefreshControl()
scrollView.refreshControl?.addTarget(context.coordinator, action: #selector(Coordinator.handleRefreshControl(sender:)), for: .valueChanged)
// *******************************************************************************
let refreshVC = UIHostingController(rootView: V()) // Type 'V' has no member 'init'
// *******************************************************************************
refreshVC.view.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
scrollView.addSubview(refreshVC.view)
return scrollView
func updateUIView(_ uiView: UIScrollView, context: Context)
class Coordinator: NSObject
var refreshScrollView: GenericRefreshView
var dataModel: T
init(_ refreshScrollView: GenericRefreshView, dataM: T)
self.refreshScrollView = refreshScrollView
self.dataModel = dataM
@objc func handleRefreshControl (sender: UIRefreshControl)
self.dataModel.refresh()
sender.endRefreshing()
【问题讨论】:
【参考方案1】:你可以要求它在外部注入,比如
struct GenericRefreshView<T, V>: UIViewRepresentable where T:ObservableObject, T:dataModel, V: View
@EnvironmentObject var dataModel: T
let contentView: V // here !!
// let builder: () -> V // alternate, as view builder
func makeCoordinator() -> Coordinator
Coordinator(self, regs: dataModel)
let size: CGSize
func makeUIView(context: Context) -> UIScrollView
let scrollView = UIScrollView()
scrollView.refreshControl = UIRefreshControl()
scrollView.refreshControl?.addTarget(context.coordinator, action: #selector(Coordinator.handleRefreshControl(sender:)), for: .valueChanged)
let refreshVC = UIHostingController(rootView: self.contentView) // here !!
...
更新:简化以避免遗漏部分,这里是使用演示
struct DemoView: View
var body: some View
GenericRefreshView(dataModel: TestViewModel(),
contentView: Text("Demo"),
size: CGSize(width: 100, height: 100))
struct GenericRefreshView<T, V>: UIViewRepresentable where T:ObservableObject, V: View
@ObservedObject var dataModel: T // << EnvironmentObject is internal, so cannot be inferred from input arguments, so not usable here
let contentView: V
let size: CGSize
【讨论】:
感谢您的回复。对不起,我不关注。您是说我应该将已经实例化的视图作为参数传递吗?在那种情况下,我不会失去通用方面吗?你能告诉我怎么称呼它吗?谢谢。 感谢您的更新,我现在已经按照您的建议工作了 - 非常感谢。我希望必须指定 GenericRefreshView以上是关于通过 Swift 泛型初始化 SwiftUI 视图的主要内容,如果未能解决你的问题,请参考以下文章
如何通过单击按钮在 Swift UI 中从一个视图导航到另一个视图
SwiftUI 将 Swift 代码作为参数传递给可重用视图