Code Block import SwiftUI |
import AppKit |
|
final class HostingCellView: NSCollectionViewItem { |
func setView<Content>(_ newValue: Content) where Content: View { |
for view in self.view.subviews { |
view.removeFromSuperview() |
} |
let view = NSHostingView(rootView: newValue) |
view.autoresizingMask = [.width, .height] |
self.view.addSubview(view) |
} |
} |
|
struct Cell: View { |
static let reuseIdentifier = NSUserInterfaceItemIdentifier("Cell") |
|
var body: some View { |
Text("Cell") |
} |
} |
|
final class HostingSupplementaryView: NSView, NSCollectionViewElement { |
override init(frame frameRect: NSRect) { |
super.init(frame: frameRect) |
} |
|
@objc required dynamic init?(coder aDecoder: NSCoder) { |
fatalError("init(coder:) has not been implemented") |
} |
|
func setView<Content>(_ newValue: Content) where Content: View { |
for view in self.subviews { |
view.removeFromSuperview() |
} |
let view = NSHostingView(rootView: newValue) |
view.autoresizingMask = [.width, .height] |
self.addSubview(view) |
} |
} |
|
struct Header: View { |
static let reuseIdentifier = NSUserInterfaceItemIdentifier("Header") |
|
var body: some View { |
Text("Header") |
} |
} |
|
struct Footer: View { |
static let reuseIdentifier = NSUserInterfaceItemIdentifier("Footer") |
|
var body: some View { |
Text("Footer") |
} |
} |
|
struct Collection: NSViewRepresentable { |
static let headerIdentifier = "ViewHeader" |
static let footerIdentifier = "ViewFooter" |
|
typealias NSViewType = NSCollectionView |
|
func makeNSView(context: Context) -> NSCollectionView { |
let view = NSCollectionView() |
view.delegate = context.coordinator |
|
view.register(HostingCellView.self, forItemWithIdentifier: Cell.reuseIdentifier) |
view.register(HostingSupplementaryView.self, forSupplementaryViewOfKind: Self.headerIdentifier, withIdentifier: Header.reuseIdentifier) |
view.register(HostingSupplementaryView.self, forSupplementaryViewOfKind: Self.footerIdentifier, withIdentifier: Footer.reuseIdentifier) |
|
view.collectionViewLayout = NSCollectionViewCompositionalLayout { (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection in |
|
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) |
let item = NSCollectionLayoutItem(layoutSize: itemSize) |
let group = NSCollectionLayoutGroup.vertical(layoutSize: itemSize, subitem: item, count: 1) |
|
let section = NSCollectionLayoutSection(group: group) |
section.orthogonalScrollingBehavior = .continuous |
|
let supplementarySize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44)) |
let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: supplementarySize, elementKind: Self.headerIdentifier, alignment: .topLeading) |
let footer = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: supplementarySize, elementKind: Self.footerIdentifier, alignment: .bottomTrailing) |
section.boundarySupplementaryItems = [header, footer] |
|
return section |
} |
|
let dataSource = NSCollectionViewDiffableDataSource<Int, Int>(collectionView: view) { (view, indexPath, sectionIndex) -> NSCollectionViewItem? in |
guard let item = view.makeItem(withIdentifier: Cell.reuseIdentifier, for: indexPath) as? HostingCellView else { |
fatalError() |
} |
item.setView(Cell()) |
return item |
} |
dataSource.supplementaryViewProvider = { (view: NSCollectionView, kind: String, indexPath: IndexPath) -> (NSView & NSCollectionViewElement)? in |
switch kind { |
case Self.headerIdentifier: |
guard let supplementary = view.makeSupplementaryView(ofKind: kind, withIdentifier: Header.reuseIdentifier, for: indexPath) as? HostingSupplementaryView else { |
fatalError() |
} |
supplementary.setView(Header()) |
return supplementary |
case Self.footerIdentifier: |
guard let supplementary = view.makeSupplementaryView(ofKind: kind, withIdentifier: Footer.reuseIdentifier, for: indexPath) as? HostingSupplementaryView else { |
fatalError() |
} |
supplementary.setView(Footer()) |
return supplementary |
default: |
return nil |
} |
} |
|
context.coordinator.dataSource = dataSource |
|
return view |
} |
|
func updateNSView(_ nsView: NSCollectionView, context: Context) { |
var snapshot = NSDiffableDataSourceSnapshot<Int, Int>() |
|
snapshot.appendSections([0]) |
// snapshot.appendItems(Array<Int>(0..<10), toSection: 0) |
|
context.coordinator.dataSource?.apply(snapshot, animatingDifferences: true) |
} |
|
func makeCoordinator() -> Coordinator { |
return Coordinator(self) |
} |
|
class Coordinator: NSObject { |
let view: Collection |
var dataSource: NSCollectionViewDiffableDataSource<Int, Int>? = nil |
|
init(_ view: Collection) { |
self.view = view |
} |
} |
} |
|
extension Collection.Coordinator: NSCollectionViewDelegate {} |