Swift Collection View: Phase 2/9

Last week you learned how to implement this feature in the SwiftCollectionView app: Display custom collection view cells in a single section of a collection view.

The Plan

Today, you will learn how to implement this feature in the SwiftCollectionView app:

Enable the user to select a cell in the collection view and display its details in another view.

Here is a QuickTime video showing result of implementing above mentioned feature in the iOS app.

To implement the new feature the iOS app, you’ll have to do the following:

  • Add a second scene on the storyboard.
  • Add a second class file in the project.
  • Connect the new scene to the new class file in Interface Builder.
  • Add controls on the scene.
  • Add constraints to the scene’s size classes.
  • Add code in the both the Master and Detail View Controller class files.

Create a New Branch

Before you perform above tasks, you have to create a new branch first. So launch the SwiftCollectionView project you worked on last week in Xcode. Next, use Xcode’s Source Control menu to create a new branch called, collection-view-cell-selection.

Add a New Scene and Class File in The Project

Now, drag a View Controller from the Object Library and drop it on the right side of the Master scene. Add a Cocoa Touch Class file in the project. Provide these options for the class; then connect the PhotoViewController.swift class file to the View Controller scene, via the Identity Inspector.

swiftcv-figure1-5
Figure 2-1

Design The Photo View Controller Scene

First, of all the Photo View Controller scene will display the selected collection view’s image in an ImageView control. Below that, the image’s name will be will shown in a label control. So design the Photo View Controller scene to look like this:

swiftcv-figure1-14
Figure 2-2

Add constraints to the default size class. Next, adjust the views in the other size classes and add constraints to them as well. While you’re adding constraints to the Photo Detail View Controller scene’s size classes, you should preview the scene in the Assistant editor.

In Interface Builder, embed the scene in a Navigation Controller. Create a segue that connect the Collection View Cell to the Photo Detail View Controller scene’s Navigation Controller scene. Select present modally from the popup menu. Select the segue and in the Attributes Inspector’s Identifier field, enter photoDetail. Rearrange the storyboard scenes so they look like this:

swiftcv-figure1-15
Figure 2-3

Use the Assistant editor to create and connect these IBOutlet variables for the Photo Detail scene’s ImageView and Label control.

swiftcv-figure1-16a swiftcv-figure1-16b
Figure 2-4 Figure 2-5

Add this variable declaration statement in the PhotoDetailViewController.swift file. It will hold the selected collection view cell’s photo name.

@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var captionLabel: UILabel!
var selectedPhotoName: String = ""

The MasterViewController File Code

You have to add code in the MasterViewController.swift to pass the selected collection view cell’s image to the PhotoDetailViewController.swift file. Start by uncommenting the prepareForSegue() function and add code shown in Listing 1 in it.

Listing 1: MasterViewController.swift file code

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
  if segue.identifier == "photoDetail" {
    // Put the destination view controller in a variable
    let controller = (segue.destinationViewController as UINavigationController).topViewController as PhotoDetailViewController

    // Pass the selectedPhoto to the destination view controller
    controller.selectedPhotoName = selectedPhotoName
  }
}

Make sure you declare the ‘selectedPhotoName’ at the top of the MasterViewController.swift file like this:

var selectedPhotoName = String()

Add code shown in listing 2, in the MasterViewController.swift file.

Listing 2: MasterViewController.swift file code

@IBAction func unwindSegue(segue: UIStoryboardSegue) {
  if segue.identifier == "showPhotos" {
  }
}

override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
  // Put the selected collection view cell's photo file name in a variable
  selectedPhotoName = imageFileNames[indexPath.row] as String

  // Pass control to the PhotoViewController
  self.performSegueWithIdentifier("photoDetail", sender:self)
}

That’s all the code you have to add in the MasterViewController.swift file. When you tap a cell in the Master View’s collection view. The collection view’s didSelectItemAtIndexPath() is fired. That function in turn calls the prepareForSegue() function.

The PhotoDetailViewController File Code

You have to add code in the PhotoDetailViewController.swift file to initialize the Photo Detail view’s controls. Start by clicking the class file to load it in the code editor. Next, replace the file’s code with the one shown in Listing 3.

Listing 3: PhotoDetailViewController.swift file code

import UIKit

class PhotoDetailViewController: UIViewController {
    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var captionLabel: UILabel!
    var selectedPhotoName: String = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        // Initialize this view controller's views
        imageView.image = UIImage(named: selectedPhotoName)

        // Convert the selectedPhoto string object to an Array
        var stringArray: Array = selectedPhotoName.componentsSeparatedByString(".")

        // Get the last element of the stringArray object and assign it to the captionLabel control
        captionLabel.text = stringArray[0]
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

Add a Button On The Navigation Bar

Now, click the Main.storyboard file, locate the Photo Detail scene, because you’ll add a button on the scene’s navigation bar. When clicked, it will return you back to the Master scene.

Get the ball rolling by dragging a Bar Button Item from the Object Library and drop it on the left side of the scene’s navigation bar. Replace the button’s text with this: Photos. Now, control-drag from the Bar Button Item to the Photo Detail scene’s Exit object. Select unwindSegue: from the pop up.

That’s it! Test the app in the iPad and iPhone simulators. It should look and function like the one shown in the QuickTime video.

  • SoulAndFoodBlog

    Hi,
    Thanks for this tutorial.
    I’m having an issue trying to have this working.
    When I click on the cell, I have :
    fatal error: Array index out of range
    at :
    selectedPhotoName = imageFileNames[indexPath.row] as String
    Any idea of what I could have forgotten here ?

    • I don’t know why you are getting this error SoulAndFoodBlog.

    • Aiyub Munshi

      use this code..

      let indexpaths = self.collectionView!.indexPathsForSelectedItems()!

      let indexpath = indexpaths[0] as NSIndexPath
      selectedPhotoName = imageFileNames[indexPath.row] as String

  • martin petrov

    Hello,

    I have a problem. When I press on a collection view cell for the first time after building project it displays nothing in the detailed view and when I press another cell it displays the info that should have been displayed the first time.

    Please help me solve that issue
    Thanks in advance

    • That’s strange behavior martin. Sorry, I don’t know how to help you.

    • Aiyub Munshi

      it is taking time to load an array.. Use GCD properly will show you in first time.

  • Merlyn Aivaliotis

    Make sure you declare the ‘selectedPhotoName’ at the top of the MasterViewController.swift file like this: var selectedPhotoName = String()

  • Jim Atwood

    Use of unresolved identifier ‘selectedPhotoName’ in MasterViewController.swift file errors. Seems like one needs a var in MasterViewController.swift for ‘selectedPhotoName’ but not sure. This code isn’t working. To see the whole MasterViewController.swift file would be very helpful.

    • Thanks Jim. I updated the post below the section entitled ‘Listing 1: MasterViewController.swift file code’. To fix this error, make sure you declare the ‘selectedPhotoName’ at the top of the MasterViewController.swift file like this: var selectedPhotoName = String()