Skip to content

Instantly share code, notes, and snippets.

View michzio's full-sized avatar

Michał Ziobro michzio

  • Cracow
View GitHub Profile
//
// ContentView.swift
// Test
//
// Created by Michal Ziobro on 03/04/2020.
// Copyright © 2020 click5 Interactive. All rights reserved.
//
import SwiftUI
@michzio
michzio / collection_view.swift
Created April 5, 2020 05:58
SwiftUI wrapper for UICollectionView with UICollectionViewCompositionalLayout
struct CollectionView<Section: Hashable & CaseIterable, Item: Hashable>: UIViewControllerRepresentable {
// MARK: - Properties
let layout: UICollectionViewLayout
let sections: [Section]
let items: [Section: [Item]]
// MARK: - Actions
let snapshot: (() -> NSDiffableDataSourceSnapshot<Section, Item>)?
let content: (_ indexPath: IndexPath, _ item: Item) -> AnyView
CollectionView(layout: createLayout(),
sections: self.sections,
items: [
.feature : Item.featureItems,
.categories : Item.categoryItems
],
supplementaryKinds: ["header", "footer"],
supplementaryContent: { kind, indexPath, item in
switch kind {
class CollectionViewController<Section, Item>: UIViewController, UICollectionViewDelegate
where Section : Hashable & CaseIterable, Item : Hashable {
// MARK: - Injections
var layout: UICollectionViewLayout! = nil
var snapshot : NSDiffableDataSourceSnapshot<Section, Item>! = nil
var content: ((_ indexPath: IndexPath, _ item: Item) -> AnyView)! = nil
var supplementaryKinds: [String]! = nil
var supplementaryContent: ((_ kind: String, _ indexPath: IndexPath, _ item: Item?) -> AnyView)? = nil
// MARK: - Setup
extension CollectionViewController {
private func configureCollectionView() {
view.addSubview(collectionView)
collectionView.register(HostingControllerCollectionViewCell<AnyView>.self, forCellWithReuseIdentifier: HostingControllerCollectionViewCell<AnyView>.reuseIdentifier)
collectionView.register(BadgeSupplementaryView.self, forSupplementaryViewOfKind: "badge", withReuseIdentifier: BadgeSupplementaryView.reuseIdentifier)
collectionView.register(EmptySupplementaryView.self, forSupplementaryViewOfKind: "badge", withReuseIdentifier: EmptySupplementaryView.reuseIdentifier)
extension CollectionViewController {
private func cellProvider(_ collectionView: UICollectionView, _ indexPath: IndexPath, _ item: Item) -> UICollectionViewCell? {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: HostingControllerCollectionViewCell<AnyView>.reuseIdentifier, for: indexPath) as? HostingControllerCollectionViewCell<AnyView> else {
fatalError("Could not load cell")
}
cell.host(content(indexPath, item))
cell.backgroundColor = .green
extension CollectionViewController {
private func supplementaryViewProvider(collectionView: UICollectionView, kind: String, indexPath: IndexPath) -> UICollectionReusableView? {
if kind == "badge" {
return badgeViewProvider(collectionView, kind, indexPath)
} else {
return contentSupplementaryProvider(collectionView, kind, indexPath)
}
}
class HostingControllerCollectionViewCell<Content: View> : UICollectionViewCell {
var controller: UIHostingController<Content>?
func host(_ view: Content, parent: UIViewController? = nil) {
if let controller = controller {
controller.rootView = view
controller.view.layoutIfNeeded()
} else {
class HostingControllerCollectionReusableView<Content: View>: UICollectionReusableView {
var controller: UIHostingController<Content>?
func host(_ view: Content, parent: UIViewController? = nil) {
if let controller = controller {
controller.rootView = view
controller.view.layoutIfNeeded()
} else {
struct CollectionView<Section: Hashable & CaseIterable, Item: Hashable>: UIViewControllerRepresentable {
// MARK: - Properties
let layout: UICollectionViewLayout
let sections: [Section]
let items: [Section: [Item]]
let supplementaryKinds: [String]
let animateChanges: Bool?
// MARK: - Actions