5

I have sucessfully implemented a 10.11 version of NSCollectionView in my Mac app. It displays the 10 items that I want, but I want the first item to be automatically selected when the app starts.

I have tried the following in the viewDidLoad and alternatively in the viewDidAppear functions;

let indexPath = NSIndexPath(forItem: 0, inSection: 0)
var set = Set<NSIndexPath>()
set.insert(indexPath)
collectionView.animator().selectItemsAtIndexPaths(set, scrollPosition:   NSCollectionViewScrollPosition.Top)

I have tried line 4 above with and without the animator

I have also tried the following in place of line 4

collectionView.animator().selectionIndexPaths = set

with and without the animator()

While they both include the index path in the selected index paths, neither actually displays the item as selected.

Any clues where I am going wrong?

rocky
  • 3,521
  • 1
  • 23
  • 31
Ferdinand Rios
  • 972
  • 6
  • 18

3 Answers3

4

I propose not to use the scroll position. In Swift 3 the following code in viewDidLoad is working for me

    // select first item of collection view
    collectionView(collectionView, didSelectItemsAt: [IndexPath(item: 0, section: 0)])
    collectionView.selectionIndexPaths.insert(IndexPath(item: 0, section: 0))

The second code line is necessary, otherwise the item is never deselected. The following is working, too

        collectionView.selectItems(at: [IndexPath(item: 0, section: 0)], scrollPosition: NSCollectionViewScrollPosition.top)

For both code snippets it is essential to have a NSCollectionViewDelegate with the function

    func collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set<IndexPath>) {
    // if you are using more than one selected item, code has to be changed
    guard let indexPath = indexPaths.first
        else { return }
    guard let item = collectionView.item(at: indexPath) as? CollectionViewItem
        else { return }
    item.setHighlight(true)
}
Erich Kuester
  • 460
  • 4
  • 11
1

According to Apple's docs, programmingly selecting items using NSCollectionView's methods won't call NSCollectionViewDelegate's didSelect method. So you have to add the highlight yourself.

override func viewDidAppear() {
    super.viewDidAppear()

    retainSelection()
}

private func retainSelection() {
    let indexPath = IndexPath(item: 0, section: 0)
    collectionView.selectItems(at: [indexPath], scrollPosition: .nearestVerticalEdge)
    highlightItems(true, atIndexPaths: [indexPath])
}

private func highlightItems(_ selected: Bool, atIndexPaths: Set<IndexPath>) {
    for indexPath in atIndexPaths {
        guard let item = collectionView.item(at: indexPath) else {continue}
        item.view.layer?.backgroundColor = (selected ? NSColor(named: "ItemSelectedColor")?.cgColor : NSColor(named: "ItemColor")?.cgColor)
    }
}
Owen Zhao
  • 3,205
  • 1
  • 26
  • 43
1

I think you use view.layer for display of selection state. And it looks like NSCollectionViewItem hasn't layer at moment. If you subclass NSCollectionViewItem try to enable wantsLayer property of it's view in viewDidLoad method.

override func viewDidAppear() {
    super.viewDidLoad()

    self.view.wantsLayer = true
}

Also you can enable wantsLayer in func collectionView(NSCollectionView, itemForRepresentedObjectAt: IndexPath) -> NSCollectionViewItem.

func collectionView(collectionView: NSCollectionView, itemForRepresentedObjectAtIndexPath
indexPath: NSIndexPath) -> NSCollectionViewItem {
    let item = self.collectionView.makeItemWithIdentifier("dataSourceItem", forIndexPath: indexPath)

    // Configure the item ...

    item.view.wantsLayer = true

    return item
 }

Then you can call

collectionView.selectionIndexPaths = set

and be sure it works.