How to use generic NSCollectionView in macOS

Issue #427

See CollectionViewHandler

Use ClickedCollectionView to detect clicked index for context menu.
Embed NSCollectionView inside NSScrollView to enable scrolling

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import AppKit

public class CollectionViewHandler<Item: Equatable, Cell: NSCollectionViewItem>
: NSObject, NSCollectionViewDataSource, NSCollectionViewDelegateFlowLayout {

public let layout = NSCollectionViewFlowLayout()
public let scrollView = NSScrollView()
public let collectionView = ClickedCollectionView()

public var items = [Item]()
public var itemSize: () -> CGSize = { .zero }
public var configure: (Item, Cell) -> Void = { _, _ in }

override init() {
super.init()

layout.minimumLineSpacing = 4
layout.sectionInset = NSEdgeInsets(top: 4, left: 4, bottom: 4, right: 4)

collectionView.dataSource = self
collectionView.delegate = self
collectionView.collectionViewLayout = layout
collectionView.allowsMultipleSelection = false
collectionView.backgroundColors = [.clear]
collectionView.isSelectable = true

collectionView.register(Cell.self, forItemWithIdentifier: Cell.itemId)

scrollView.documentView = collectionView
}

// MARK: - Items

public func add(item: Item) {
items.insert(item, at: 0)
let indexPath = IndexPath(item: 0, section: 0)
collectionView.animator().insertItems(at: Set(arrayLiteral: indexPath))
}

public func remove(item: Item) {
guard let index = items.firstIndex(where: { $0 == item }) else {
return
}

remove(index: index)
}

public func remove(index: Int) {
items.remove(at: index)
let indexPath = IndexPath(item: index, section: 0)
collectionView.animator().deleteItems(at: Set(arrayLiteral: indexPath))
}

// MARK: - NSCollectionViewDataSource

public func numberOfSections(in collectionView: NSCollectionView) -> Int {
return 1
}

public func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}

public func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {

let cell = collectionView.makeItem(withIdentifier: Cell.itemId, for: indexPath) as! Cell
let item = items[indexPath.item]
configure(item, cell)
return cell
}

// MARK: - NSCollectionViewDelegateFlowLayout

public func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {

return itemSize()
}
}

Comments