// // SwiftUICollectionView.swift // Sentry // // Created by Simon Westerlund on 2019-12-29. // Copyright © 2019 Simon Westerlund. All rights reserved. // import SwiftUI final class UIHostingControllerCollectionViewCell: UICollectionViewCell { private var view: UIView? { willSet { view?.removeFromSuperview() } } override func prepareForReuse() { super.prepareForReuse() view?.removeFromSuperview() } func configureForDisplay(with item: Content) { view = UIHostingController(rootView: item).view embedView(view) } func select(with item: Content) { let selectedItem = item.modifier(SelectedViewModifier(selected: true)) view = UIHostingController(rootView: selectedItem).view embedView(view) } private func embedView(_ view: UIView?) { guard let view = view else { return } contentView.addSubview(view) contentView.backgroundColor = .clear backgroundColor = .clear view.frame = contentView.bounds view.autoresizingMask = [.flexibleHeight, .flexibleWidth] } } final class DataSource: NSObject, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { @Binding var selectedIndexPath: IndexPath let items: [Content] init(items: [Content], selectedIndexPath: Binding) { self.items = items self._selectedIndexPath = selectedIndexPath } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return items.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! UIHostingControllerCollectionViewCell let item = items[indexPath.row] if selectedIndexPath == indexPath { cell.select(with: item) } else { cell.configureForDisplay(with: item) } return cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { return UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let height = collectionView.frame.height return CGSize(width: height * 4 / 3, height: height) } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { if let cell = collectionView.cellForItem(at: selectedIndexPath) as? UIHostingControllerCollectionViewCell { let item = items[selectedIndexPath.row] cell.configureForDisplay(with: item) } selectedIndexPath = indexPath if let cell = collectionView.cellForItem(at: selectedIndexPath) as? UIHostingControllerCollectionViewCell { let item = items[selectedIndexPath.row] cell.select(with: item) } } } struct SwiftUICollectionView: UIViewRepresentable { typealias UIViewType = UICollectionView let dataSource: DataSource let collectionView: UIViewType init(cells: [Content], selectedIndexPath: Binding) { dataSource = DataSource(items: cells, selectedIndexPath: selectedIndexPath) let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) } func makeUIView(context: UIViewRepresentableContext) -> UICollectionView { collectionView.register(UIHostingControllerCollectionViewCell.self, forCellWithReuseIdentifier: "cell") collectionView.dataSource = dataSource collectionView.delegate = dataSource collectionView.backgroundColor = .clear return collectionView } func updateUIView(_ uiView: UICollectionView, context: UIViewRepresentableContext) {} func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject { var control: SwiftUICollectionView init(_ control: SwiftUICollectionView) { self.control = control } } }