问题
I have this CustomScrollView which wraps my HomeView and if you pull down it fetches new data.
It works fine but the thing is that I want to reuse this in multiple views and I do not want to create a copy of this for each of my views.
I have tried to do this var rootView: View but it throws an error saying View is not convertible to HomeView.
So there are two thing witch should be generic. HomeView() and HomeViewModel.
Any idea how to achieve that?
struct CustomScrollView : UIViewRepresentable {
var width : CGFloat
var height : CGFloat
let viewModel = HomeViewModel()
func makeCoordinator() -> Coordinator {
Coordinator(self, homeViewModel: viewModel)
}
func makeUIView(context: Context) -> UIScrollView {
let control = UIScrollView()
control.refreshControl = UIRefreshControl()
control.refreshControl?.addTarget(context.coordinator, action: #selector(Coordinator.handleRefreshControl), for: .valueChanged)
let childView = UIHostingController(rootView: HomeView())
childView.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
control.addSubview(childView.view)
return control
}
func updateUIView(_ uiView: UIScrollView, context: Context) { }
class Coordinator: NSObject {
var control: CustomScrollView
var homeViewModel: HomeViewModel
init(_ control: CustomScrollView, homeViewModel: HomeViewModel) {
self.control = control
self.homeViewModel = homeViewModel
}
@objc func handleRefreshControl(sender: UIRefreshControl) {
sender.endRefreshing()
homeViewModel.loadPackages()
}
}
}
回答1:
Here is possible approach (compiled with Xcode 11.4)
Usage:
CustomScrollView(width: 100, height: 100,
viewModel: HomeViewMode()) {
HomeView()
}
Generic type:
protocol CustomViewModel {
func loadPackages()
}
// It is used generic ViewBuilder pattern for content
struct CustomScrollView<Content: View, VM: CustomViewModel> : UIViewRepresentable {
var width : CGFloat
var height : CGFloat
let viewModel: VM
let content: () -> Content
init(width: CGFloat, height: CGFloat, viewModel: VM, @ViewBuilder content: @escaping () -> Content) {
self.width = width
self.height = height
self.viewModel = viewModel
self.content = content
}
func makeUIView(context: Context) -> UIScrollView {
let control = UIScrollView()
control.refreshControl = UIRefreshControl()
control.refreshControl?.addTarget(context.coordinator, action: #selector(Coordinator.handleRefreshControl), for: .valueChanged)
let childView = UIHostingController(rootView: content())
childView.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
control.addSubview(childView.view)
return control
}
func updateUIView(_ uiView: UIScrollView, context: Context) { }
class Coordinator: NSObject {
var control: CustomScrollView<Content, VM>
var viewModel: VM
init(_ control: CustomScrollView, viewModel: VM) {
self.control = control
self.viewModel = viewModel
}
@objc func handleRefreshControl(sender: UIRefreshControl) {
sender.endRefreshing()
viewModel.loadPackages()
}
}
}
来源:https://stackoverflow.com/questions/61371525/swiftui-generic-pull-to-refresh-view