CollectionView

open class CollectionView : ScrollView, NSDraggingSource

A Collection View manages the presentation of items, your app’s main job is to provide the data that those items are to represent.

A collection view gets its data from the data source, which is an object that conforms to the CollectionViewDataSource protocol. Data provided by the data source is represented items, which can also be organized into sections, and ultimately displayed as cells.

Gathings Data

The data source only has 3 requirements, provide the number of sections, the number of items, and a cell for each item. For performance, cells in a collection view are reusable since only a subset of all the items will often be visbile.

Before you can load a cell, you need to register the cells you will need to represet your data. Cells can be registered from a nib or from a class using register(class:forCellWithReuseIdentifier:) or register(nib:forCellWithReuseIdentifier:). The reuse identifier will later be use to get instances of the cell.

To create the cells for each item in your data, implement the data source method func collectionView(_:cellForItemAt:) -> CollectionViewCell. In here you will call dequeueReusableCell(withReuseIdentifier:for:) which will load an instance of the cell your previously registered for that resuse identifier. After you have dequeued the cell, update it as needed to properly represent the object at the given index path in your data, then return it.

Laying Out Items

After the data source has provided all the cells to be displayed, the collection view looks to its CollectionViewLayout to determine where to place each one. The base layout object is designed to be subclassed to generate layout information for different use cases. The goal of a layout is to be able to provide information about the layout to the collection view quickly, this inlcudes the location of each cell, the overall size of all the items, etc.

The following layouts are provided for common uses, for more custom layouts, create a custom CollectionViewLayout subclass.

  • CollectionViewColumnLayout
  • CollectionViewListLayout
  • CollectionViewFlowLayout
  • CollectionViewHorizontalLayout
  • The object that acts as the delegate to the collection view

    Declaration

    Swift

    @objc
    public weak var delegate: CollectionViewDelegate?
  • The object that provides data for the collection view

    Declaration

    Swift

    public weak var dataSource: CollectionViewDataSource?
  • The content view in which all cells and views are displayed

    Declaration

    Swift

    public var contentDocumentView: CollectionViewDocumentView { get }
  • Register a class to be initialized when loading reusable cells

    Declaration

    Swift

    public func register(class cellClass: CollectionViewCell.Type, forCellWithReuseIdentifier identifier: String)

    Parameters

    cellClass

    A CollectionViewCell subclass

    identifier

    A reuse identifier to deque cells of this class

  • Register a nib to be loaded as reusable cells

    Declaration

    Swift

    public func register(nib: NSNib, forCellWithReuseIdentifier identifier: String)

    Parameters

    nib

    The nib for the cell

    identifier

    A reuse identifier to deque cells from this nib

  • Register a class to be initialized when loading reusable supplementary views

    Declaration

    Swift

    public func register(class viewClass: CollectionReusableView.Type, forSupplementaryViewOfKind kind: String, withReuseIdentifier identifier: String)

    Parameters

    viewClass

    A CollectionReusableview subclass

    elementKind

    The kind of element the class represents

    identifier

    A reuse identifier to deque views of this class

  • Register a nib to be loaded as a supplementary view

    Note

    The nib must contain a single view whose class is set to CollectionReusableview.

    Declaration

    Swift

    public func register(nib: NSNib, forSupplementaryViewOfKind elementKind: String, withReuseIdentifier identifier: String)

    Parameters

    nib

    The nib for the view

    elementKind

    The kind of element this nib represents

    identifier

    A reuse identifier to deque views from this nib

  • Retrieve a cell for a given reuse identifier and index path.

    If no reusable cell is available, one is created from the registered class/nib.

    Declaration

    Swift

    public final func dequeueReusableCell(withReuseIdentifier identifier: String, for indexPath: IndexPath) -> CollectionViewCell

    Parameters

    identifier

    The reuse identifier

    indexPath

    The index path specifying the location of the supplementary view to load.

    Return Value

    A valid CollectionReusableView

  • Returns a reusable supplementary view located by its identifier and kind.

    Declaration

    Swift

    public final func dequeueReusableSupplementaryView(ofKind elementKind: String, withReuseIdentifier identifier: String, for indexPath: IndexPath) -> CollectionReusableView

    Parameters

    elementKind

    The kind of supplementary view to retrieve. This value is defined by the layout object. This parameter must not be nil.

    identifier

    The reuse identifier for the specified view.

    indexPath

    The index path specifying the location of the cell to load

    Return Value

    A valid CollectionViewCell

  • A view atop the collection view used to display non-scrolling accessory views

    Declaration

    Swift

    public var floatingContentView: NSView { get }
  • Adds the given view to the floating content view

    Declaration

    Swift

    public func addAccessoryView(_ view: NSView)

    Parameters

    view

    The view to add

  • Returns the number of sections displayed by the collection view.

    Declaration

    Swift

    public var numberOfSections: Int { get }

    Return Value

    The number of sections

  • Returns the number of items in the specified section.

    Declaration

    Swift

    public func numberOfItems(in section: Int) -> Int

    Parameters

    section

    The index of the section for which you want a count of the items.

    Return Value

    The number of items in the specified section

  • Reloads all the data and views in the collection view

    Declaration

    Swift

    open func reloadData()
  • The layout used to organize the collected view’s items.

    Note

    Assigning a new layout object to this property does NOT apply the layout to the collection view. Call reloadData() or reloadLayout(_:) to do so.

    Declaration

    Swift

    public var collectionViewLayout: CollectionViewLayout { get set }
  • The visible rect of the document view that is visible

    Declaration

    Swift

    public var contentVisibleRect: CGRect { get }
  • The total size of all items/views

    Declaration

    Swift

    open override var contentSize: NSSize { get }
  • The offset of the content view

    Declaration

    Swift

    public var contentOffset: CGPoint { get set }
  • Force layout of all items, not just those in the visible content area

    Note

    This is not recommended for large data sets. It can be useful for smaller collection views to better manage transitions/animations.

    Declaration

    Swift

    public var prepareAll: Bool
  • Returns the frame for the specified section

    Declaration

    Swift

    open func frameForSection(at index: Int) -> CGRect?

    Parameters

    indexPath

    The index path of the section for which you want the frame

  • Reload the data (section & item counts) when the collectionView bounds change. Defaults to false.

    Note

    This will only be applied if the layout is also invalidated via shouldInvalidateLayout(forBoundsChange:)

  • Discussion: Set to true if the number of sections or items per section can change depending on the collection view’s size For example if you want to limit the size of a section but maintain item size, you can calculate the number of items that will fit in the section based on the size of the collection view and return that value in collectionView(_:numberOfItemsIn:) from the collection views data source.

    +----------+      +-----------------+
    |          |      |                 |
    |  +----+  |      |  +----+ +----+  |
    |  |    |  |      |  |    | |    |  |
    |  |    |  |      |  |    | |    |  |
    |  +----+  | +--> |  +----+ +----+  |
    |          |      |                 |
    +----------+      +-----------------+
    |Section 2 |      |Section 2        |
    +----------+      +-----------------+
    |          |      |                 |
    +----------+      +-----------------+
    
  • Declaration

    Swift

    public var reloadDataOnBoundsChange: Bool
  • A Boolean value indicating whether the collection view layout should be reloaded on the next view layout. needsLayout is also if needed.

    Declaration

    Swift

    open var needsLayoutReload: Bool { get set }
  • Reload the collection view layout and apply the updated frames to the cells/views.

    Declaration

    Swift

    public func reloadLayout(_ animated: Bool, scrollPosition: CollectionViewScrollPosition = .nearest, completion: AnimationCompletion? = nil)

    Parameters

    animated

    If the layout should be animated

    scrollPosition

    Where (if any) the scroll position should be pinned

  • Returns true if the collection view is currently scrolling

    Declaration

    Swift

    public internal(set) var isScrolling: Bool
  • Returns the current velocity of a scroll in points/second

    Declaration

    Swift

    public private(set) var scrollVelocity: CGPoint
  • Returns the peak valocity of a scroll during the last scrolling session

    Example Usage

    If your cells require complex loading that may slow scrolling performance, peakScrollVelocity can be used to determine if the cell content should be reduced or delayed until after the scrolling ends.

    For example in CollectionViewCell

    override func viewDidDisplay() {
       if self.collectionView?.isScrolling != true ||  (self.collectionView?.peakScrollVelocity.maxAbsVelocity ?? 0) < 200 {
           // load complex content
       }
       else {
           // Wait until we are done scrolling
       }
    }
    
    func loadContent() { Do complex loading }
    

    Then, in your collection view’s delegate

    func collectionViewDidEndScrolling(_ collectionView: CollectionView, animated: Bool) {
       guard collectionView.peakScrollVelocity.maxAbsVelocity > 200 else { return }
       for ip in collectionView.indexPathsForVisibleItems {
           if let c = collectionView.cellForItem(at:ip) as? MyCellClass {
               c.loadContent
           }
       }
    }
    

    Declaration

    Swift

    public private(set) var peakScrollVelocity: CGPoint
  • Returns the lowest index path of all visible items

    Declaration

    Swift

    open var indexPathsForVisibleSections: [IndexPath] { get }
  • Returns the lowest index path of all visible items

    Declaration

    Swift

    open var indexPathForFirstVisibleItem: IndexPath? { get }
  • Same as indexPathForFirstVisibleItem but doesn’t ask the delegate for a suggestion. This is a convenient variable to use in collectionViewLayoutAnchor(_:) but asking the delegate within is not possibe.

    Declaration

    Swift

    open var _indexPathForFirstVisibleItem: IndexPath? { get }
  • The duration of animations when performing animated layout changes

    Declaration

    Swift

    public var animationDuration: TimeInterval
  • Perform multiple updates to be applied together

    Declaration

    Swift

    public func performBatchUpdates(_ updates: (() -> Void), completion: AnimationCompletion?)

    Parameters

    updates

    A closure in which to apply the desired changes

    completion

    A closure to call when the animation finished

  • Insert sections at the given indexes

    Declaration

    Swift

    public func insertSections(_ sections: IndexSet, animated: Bool)

    Parameters

    sections

    The sections to insert

    animated

    If the update should be animated

    Note

    If called within performBatchUpdate(_:completion:) sections should be the final indexes after other updates are applied
  • Remove sections and their items

    Declaration

    Swift

    public func deleteSections(_ sections: IndexSet, animated: Bool)

    Parameters

    sections

    The sections to delete

    Note

    If called within performBatchUpdate(_:completion:) sections should be the index prior to any other updates
    animated

    If the update should be animated

  • Move a section and its items

    Note

    If called within performBatchUpdate(_:completion:):

  • Source should be the index prior to any other updates

  • Destination should be the final index after all other updates

  • Declaration

    Swift

    public func moveSection(_ section: Int, to newSection: Int, animated: Bool)

    Parameters

    section

    The source index of the section to move

    newSection

    The destination index to move the section to

    animated

    If the move should be animated

  • Insert items at specific index paths

    Declaration

    Swift

    public func insertItems(at indexPaths: [IndexPath], animated: Bool)

    Parameters

    indexPaths

    The index paths at which to insert items.

    animated

    If the insertion should be animated

  • Deletes the items at the specified index paths.

    Declaration

    Swift

    public func deleteItems(at indexPaths: [IndexPath], animated: Bool)

    Parameters

    indexPaths

    The index paths for the items you want to delete

    animated

    If the updates should be animated

  • Reload the items and the given index paths.

    The cells will be reloaded, asking the data source for the cell to replace with.

    Declaration

    Swift

    public func reloadItems(at indexPaths: [IndexPath], animated: Bool)

    Parameters

    indexPaths

    The index paths for the items you want to reoad

    animated

    If the updates should be animated

  • Moves the item from it’s current index path to another

    Declaration

    Swift

    public func moveItem(at indexPath: IndexPath, to destinationIndexPath: IndexPath, animated: Bool)

    Parameters

    indexPath

    The index path for the item to move

    destinationIndexPath

    The index path to move the item to

    animated

    If the update should be animated

  • If true, the delegate’s collectionView(_:,mouseMovedToSection:) will be notified when the cursor is within a section frame

    Declaration

    Swift

    public var trackSectionHover: Bool { get set }
  • If the collection view should allow selection of its items

    Declaration

    Swift

    public var allowsSelection: Bool
  • Determine how item selections are managed

    • normal: Clicking an item selects the item and deselects others (given no modifier keys are used)
    • multi: Clicking an item will add it to the selection, clicking again will deselect it

    Declaration

    Swift

    public enum SelectionMode
  • Determines what happens when an item is clicked

    Declaration

    Swift

    public var selectionMode: CollectionView.SelectionMode
  • Allows the selection of multiple items via modifier keys (command & shift) (default true)

    Declaration

    Swift

    public var allowsMultipleSelection: Bool
  • If true, clicking empty space will deselect all items (default true)

    Declaration

    Swift

    public var allowsEmptySelection: Bool
  • If true, programatic changes will be reported to the delegate (i.e. selections)

    Declaration

    Swift

    public var notifyDelegate: Bool
  • If true, selecting an already selected item will notify the delegate (default true)

    Declaration

    Swift

    public var repeatSelections: Bool
  • The index path of the highlighted item, if any

    Declaration

    Swift

    public internal(set) var indexPathForHighlightedItem: IndexPath? { get set }
  • Manually set the highlighted item reguardless of the cursor location

    This can be use to adust the highlighted item in response to key events

    Declaration

    Swift

    public func highlightItem(at indexPath: IndexPath?, animated: Bool)

    Parameters

    indexPath

    The index path of the item to highlight

    animated

    If the change should be animated

  • Returns the index paths for all selected items

    Declaration

    Swift

    public final var indexPathsForSelectedItems: Set<IndexPath> { get }
  • Returns the index paths for all selected items ordered from first to last

    Declaration

    Swift

    public final var sortedIndexPathsForSelectedItems: [IndexPath] { get }
  • Returns if the item at a given index path is selected

    Declaration

    Swift

    public final func itemAtIndexPathIsSelected(_ indexPath: IndexPath) -> Bool

    Parameters

    indexPath

    The index path of the item to check

    Return Value

    True if the item at indexPath is selected

  • Selects all items in the collection view

    Note

    The delegate will not be notified of the changes

    Declaration

    Swift

    public func selectAllItems(_ animated: Bool = true)

    Parameters

    animated

    If the selections should be animated

  • Select an item at a given index path

    Note

    The delegate will not be notified of the changes

    Declaration

    Swift

    public func selectItem(at indexPath: IndexPath, animated: Bool, scrollPosition: CollectionViewScrollPosition = .none)

    Parameters

    indexPath

    The indexPath to select

    animated

    If the selections should be animated

    scrollPosition

    The position to scroll the selected item to

  • Select the items at the given index paths

    Note

    The delegate will not be notified of the changes

    Declaration

    Swift

    public func selectItems<C: Collection>(at indexPaths: C, animated: Bool, scrollPosition: CollectionViewScrollPosition = .none) where C.Element == IndexPath

    Parameters

    indexPaths

    The index paths of the items you want to select

    animated

    If the selections should be animated

  • Deselect cells at given index paths

    Note

    The delegate will not be notified of the changes

    Declaration

    Swift

    public func deselectItems<C>(at indexPaths: C, animated: Bool) where C : Collection, C.Element == IndexPath

    Parameters

    indexPaths

    The index paths to deselect

    animated

    If the deselections should be animated

  • Deselect all items in the collection view

    Note

    The delegate will not be notified of the changes

    Declaration

    Swift

    public func deselectAllItems(_ animated: Bool = false)

    Parameters

    animated

    If the delselections should be animated

  • Deselect the item at a given index path

    Note

    The delegate will not be notified of the changes

    Declaration

    Swift

    public func deselectItem(at indexPath: IndexPath, animated: Bool)

    Parameters

    indexPath

    The index path for the item to deselect

    animated

    If the deselection should be animated

  • Returns all visible cells in the collection view

    Declaration

    Swift

    public final var visibleCells: [CollectionViewCell] { get }
  • / Returns the index paths for all visible cells in the collection view

    Declaration

    Swift

    public final var indexPathsForVisibleItems: [IndexPath] { get }
  • Returns true if the item at the index path is visible

    Declaration

    Swift

    public final func itemAtIndexPathIsVisible(_ indexPath: IndexPath) -> Bool

    Parameters

    indexPath

    The index path of an item in the collection view

    Return Value

    True if the item is visible

  • Returns the cell at a given index path if it is visible

    Declaration

    Swift

    public final func cellForItem(at indexPath: IndexPath) -> CollectionViewCell?

    Parameters

    indexPath

    An index path of an item in the collection view

    Return Value

    The cell at the indexpath, or nil if it is not visible

  • Returns the index path for a cell in the collection view

    Declaration

    Swift

    public final func indexPath(for cell: CollectionViewCell) -> IndexPath?

    Parameters

    cell

    A cell in the collection view

    Return Value

    The index path of the cell, or nill if it is not visible in the collection view

  • Returns a index path for the item at a given point

    Declaration

    Swift

    public func indexPathForItem(at point: CGPoint) -> IndexPath?

    Parameters

    point

    A point within the collection views contentVisibleRect

    Return Value

    The index path of the item at point, if any

  • Returns the first index path within a given distance of a point

    Declaration

    Swift

    public func firstIndexPathForItem(near point: CGPoint, radius: CGFloat) -> IndexPath?

    Parameters

    point

    A point within the contentDocumentView’s frame

    radius

    The distance around the point to check

    Return Value

    The index path for a matching item or nil if no items were found

  • Returns the first index path found intersecting a given rect

    Declaration

    Swift

    public func firstIndexPathForItem(in rect: CGRect) -> IndexPath?

    Parameters

    rect

    A rect within the contentDocumentView’s frame

    Return Value

    The index path for the matching item or nil if no items were found

  • Returns all items intersecting a given rect

    Declaration

    Swift

    public func indexPathsForItems(in rect: CGRect) -> [IndexPath]

    Parameters

    rect

    A rect within the contentDocumentView’s frame

    Return Value

    The index paths for all items in the rect. Will be empty if no items were found

  • Returns the indexPath for the section that contains the given point

    Declaration

    Swift

    public final func indexPathForSection(at point: CGPoint) -> IndexPath?

    Parameters

    point

    The point the section must contain

    Return Value

    The index path for the section contianing the point

  • Returns all visible cells in the collection view

    Declaration

    Swift

    public final var visibleSupplementaryViews: [CollectionReusableView] { get }
  • Returns the index path for a supplementary view

    Declaration

    Swift

    public final func indexPath(forSupplementaryView view: CollectionReusableView) -> IndexPath?

    Parameters

    view

    The supplementary view for which you want the index path

    Return Value

    The index path for the view

  • Returns the visible supplementary view of the given kind at indexPath

    Declaration

    Swift

    public final func supplementaryViews(forElementKind kind: String, at indexPath: IndexPath) -> CollectionReusableView?

    Parameters

    kind

    The kind of the supplementary view

    indexPath

    The index path of the supplementary view

    Return Value

    The view of kind at the given index path

  • Returns the visible supplementary view of the given kind at indexPath

    Declaration

    Swift

    public final func supplementaryView(forElementKind kind: String, at indexPath: IndexPath) -> CollectionReusableView?

    Parameters

    kind

    The kind of the supplementary view

    indexPath

    The index path of the supplementary view

    Return Value

    The view of kind at the given index path

  • Scroll an item into view

    Declaration

    Swift

    public func scrollItem(at indexPath: IndexPath, to scrollPosition: CollectionViewScrollPosition, animated: Bool, completion: AnimationCompletion?)

    Parameters

    indexPath

    The index path of the item to scroll to

    scrollPosition

    The position to scroll the item to within the visible frame

    animated

    If the scroll should be animated

    completion

    A closure to call on completion of the scroll

  • Scroll an given rect into view

    Declaration

    Swift

    public func scrollRect(_ aRect: CGRect, to scrollPosition: CollectionViewScrollPosition, animated: Bool, completion: AnimationCompletion?)

    Parameters

    aRect

    The rect within the contentDocumentView to scroll to

    scrollPosition

    The position to scroll the rect to

    animated

    If the scroll should be animated

    completion

    A closure to call on completion of the scroll

  • The index paths for items included in the currect dragging session

    Declaration

    Swift

    public var indexPathsForDraggingItems: [IndexPath] { get }