Collection Views in OS X Tutorial

In this collection views in OS X tutorial, you’ll discover the joy of arranging things in beautiful, flowing interfaces for the desktop. By Gabriel Miro.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Configure the Collection View Layout

You’ve got options: You can set the initial layout and some of its attributes in Interface Builder, or you can set them programmatically.

For SlidesMagic, you’ll take the programmatic approach.

Open ViewController.swift and add the following method to ViewController:

private func configureCollectionView() {
  // 1
  let flowLayout = NSCollectionViewFlowLayout()
  flowLayout.itemSize = NSSize(width: 160.0, height: 140.0)
  flowLayout.sectionInset = NSEdgeInsets(top: 10.0, left: 20.0, bottom: 10.0, right: 20.0)
  flowLayout.minimumInteritemSpacing = 20.0
  flowLayout.minimumLineSpacing = 20.0
  collectionView.collectionViewLayout = flowLayout
  // 2
  view.wantsLayer = true
  // 3
  collectionView.layer?.backgroundColor = NSColor.blackColor().CGColor
}

Here’s what you’re doing in this method:

  1. Creating an NSCollectionViewFlowLayout and setting its attributes and the collectionViewLayout property of the NSCollectionView.
  2. For optimal performance, NSCollectionView is designed to be layer-backed. So, you’re setting an ancestor’s wantsLayer property to true.
  3. Making an addition related to the layer that’s specific to SlidesMagic, setting the collection view’s background color to black.

You need to call this method when the view is created, so add this to the end of viewDidLoad():

configureCollectionView()

Build and run:

BlackView

At this point, you have a black background and a layout. You’ve set the stage for your magic show!

Loading Items in the Collection View

To load items, you need to call its reloadData() method, which causes the collection view to discard and redisplay any currently visible items.

You’d typically call this method when the model changes.

Open ViewController.swift and add this code at the end of loadDataForNewFolderWithUrl(_:):

collectionView.reloadData()

This makes it so that selecting File \ Open Another Folder… calls this method. it loads a new model then calls reloadData().

Creating a Collection View Item

Just because you removed NSCollectionViewItem from the storyboard doesn’t mean you don’t need it. :] Here’s how to bring it back the right way.

Go to File \ New \ File…, select OS X \ Source \ Cocoa Class and click Next.

Set the Class field to CollectionViewItem, the Subclass of field to NSCollectionViewItem, and check Also create XIB for user interface.

CreateColViewItems

Click Next, and in the save dialog, select Controllers from Group and click Create.

Open CollectionViewItem.swift and replace the whole class with this:

class CollectionViewItem: NSCollectionViewItem {

  // 1
  var imageFile: ImageFile? {
    didSet {
      guard viewLoaded else { return }
      if let imageFile = imageFile {
        imageView?.image = imageFile.thumbnail
        textField?.stringValue = imageFile.fileName
      } else {
        imageView?.image = nil
        textField?.stringValue = ""
      }
    }
  }
  
  // 2
  override func viewDidLoad() {
    super.viewDidLoad()
    view.wantsLayer = true
    view.layer?.backgroundColor = NSColor.lightGrayColor().CGColor
  }
}

In here, you:

  1. Define the imageFile property that holds the model object to be presented in this item. When set, its didSet property observer sets the content of the item’s image and label.
  2. Change the background color to the item’s view.

Add Controls to the View

The View in the nib is the root view for a subtree of controls to be displayed in the item. You’re going to add an image view and a label for the file name.

Open CollectionViewItem.xib.

Add an NSImageView:

ImageAL1

  1. From the Object Library, add an Image View to View.
  2. Select and click Pin from the Auto Layout toolbar to set its constraints.
  3. Set the top, leading and trailing constraints to 0, the bottom to 30 and click Add 4 Constraints.
  4. To fix the Auto Layout issues, select Editor \ Resolve Auto Layout Issues \ Update Frames.

ImageAL2

Add a label:

LabelInPlace

Screen Shot 2015-12-09 at 20.11.30

  1. From the Object Library, add a Label below the Image View.
  2. Click the Pin button. Set the top, bottom, trailing and leading constraints to 0, and then click Add 4 Constraints.
  3. Select Editor \ Resolve Auto Layout Issues \ Update Frames to update its position.

Select the Label, and in the Attributes Inspector set the following attributes:

  1. Alignment to center
  2. Text Color to white
  3. Line Break to Truncate Tail

ConfigLabel

Now you need to connect the controls to the imageView and the textField outlets:

  1. Select File’s Owner and show the Connections Inspector.
  2. Next, drag from the button next imageView to the Image View control to connect them.
  3. In the same way, connect the textField outlet to Label.

OwnerOutlets2

Add a Top Level CollectionViewItem to the Nib

The File’s Owner in the nib — of type CollectionViewItem — is just a placeholder. You still need to instantiate it.

CollectionView's method makeItemWithIdentifier(_:forIndexPath:) instantiates the collection view item, and it requires the nib to contain a single top-level instance of either NSCollectionViewItem or a subclass thereof.

You need to make it appear.

Drag a Collection View Item from the Object Library and drop it into Document Outline. Select it, and in the Identity Inspector, set its Class to CollectionViewItem.

TopLevelObject

Populate the Collection View

You need to implement the data source methods so the view knows the answers to these questions:

  1. How many sections are in the collection?
  2. How many items are in each section?
  3. Which item is associated with a specified index path?

Meet your data source method: NSCollectionViewDataSource protocol.

Put it into action now — open ViewController.swift and add the following extension at the end of the file:

extension ViewController : NSCollectionViewDataSource {
  
  // 1
  func numberOfSectionsInCollectionView(collectionView: NSCollectionView) -> Int {
    return imageDirectoryLoader.numberOfSections
  }
  
  // 2
  func collectionView(collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
    return imageDirectoryLoader.numberOfItemsInSection(section)
  }
  
  // 3
  func collectionView(collectionView: NSCollectionView, itemForRepresentedObjectAtIndexPath indexPath: NSIndexPath) -> NSCollectionViewItem {
    
    // 4
    let item = collectionView.makeItemWithIdentifier("CollectionViewItem", forIndexPath: indexPath)
    guard let collectionViewItem = item as? CollectionViewItem else {return item}
    
    // 5
    let imageFile = imageDirectoryLoader.imageFileForIndexPath(indexPath)
    collectionViewItem.imageFile = imageFile
    return item
  }
  
}
  1. This method provides the number of sections. When your app doesn’t support sections, you can omit this method because a single section will be assumed. When SlidesMagic launches, the model imageDirectoryLoader is set to return the value 1.
  2. This is one of two required methods for NSCollectionViewDataSource. Here you return the number of items in the section specified by the section parameter. Upon launch, SlidesMagic has a single section, so you set the model to return the total number of images in the folder.
  3. This is the second required method. It returns a collection view item for a given indexPath.
  4. The collection view’s method makeItemWithIdentifier(_:forIndexPath:) instantiates an item from a nib where its name equals the value of the identifier parameter. In this case, it’s "CollectionViewItem". First, it attempts to reuse an unused item of the requested type, and if nothing is available it creates a new one.
  5. This code gets the model object for the given NSIndexPath and sets the content of the image and the label.
Note: The ability of the collection view to recycle unused collection view items provides a scalable solution for large collections. Items associated with model objects that aren’t visible are the objects that get recycled.
Gabriel Miro

Contributors

Gabriel Miro

Author

Over 300 content creators. Join our team.