I have a SwiftUI View that displays a UIViewControllerRepresentable which is wrapped in a NavigationView. I've gotten it all working to what I want though now I want to be able to push from the collection view another View when the user taps in a cell. The issue I am facing is that the Coordinator does not have access to the navigation controller. Is there a better implementation to this?
This is the initial SwiftUI View
import SwiftUI
struct ExploreView: View {
@ObservedObject var exploreViewVM = ExploreViewViewModel()
var body: some View {
NavigationView {
CollectionView(products: exploreViewVM.products)
}
}
}
struct ExploreView_Previews: PreviewProvider {
static var previews: some View {
ExploreView()
}
}
This is the collectionView wrapper. As you can see in the didSelectItemAt function, I am trying to wrap the view within a HostingController. I know it does not make any sense to instantiate the navigation controller with the root of hosting controller and then push to it. Though I am not sure how to go about it and would appreciate any help.
import SwiftUI
import SDWebImage
struct CollectionView: UIViewControllerRepresentable {
var products: [Product]
let cellId = "cellId"
typealias UIViewControllerType = UICollectionViewController
func makeUIViewController(context: Context) -> UICollectionViewController {
let collectionView = UICollectionViewController(collectionViewLayout: createLayout())
collectionView.collectionView.backgroundColor = .white
collectionView.collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
collectionView.collectionView.dataSource = context.coordinator
collectionView.collectionView.delegate = context.coordinator
return collectionView
}
func createLayout() -> UICollectionViewCompositionalLayout {
return UICollectionViewCompositionalLayout { sectionNumber, env in
let item = NSCollectionLayoutItem(layoutSize: .init(widthDimension: .fractionalWidth(0.3333), heightDimension: .fractionalWidth(0.3333)))
item.contentInsets.trailing = 1
item.contentInsets.bottom = 1
let group = NSCollectionLayoutGroup.horizontal(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .estimated(500)), subitems: [item])
group.contentInsets.leading = 1
let section = NSCollectionLayoutSection(group: group)
return section
}
}
func updateUIViewController(_ uiViewController: UICollectionViewController, context: Context) {
}
class Coordinator: NSObject, UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return parent.products.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: parent.cellId, for: indexPath)
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.layer.masksToBounds = true
imageView.sd_setImage(with: URL(string: parent.products[indexPath.item].imageUrl)) { (image, _, _, _) in
imageView.image = image
}
cell.backgroundView = imageView
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let controller = UIHostingController(rootView: ProductView(product: parent.products[indexPath.item]))
let navigation = UINavigationController(rootViewController: controller)
navigation.pushViewController(controller, animated: true)
}
let parent: CollectionView
init(_ parent: CollectionView) {
self.parent = parent
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}