by

UICollectionView is great for displaying information in a grid or other custom layouts. In iOS 6 you’ll see collection views most likely used in many apps such as the podcasts app for viewing different podcasts. Since in most cases you’ll want to use UICollectionViewController, we’ll focus on that for this recipe.

Assumptions

You are familiar with Xcode and setting up a single view controller. If not check out our recipe on Xcode first.

Setting Up The View

Go ahead and create a new single view controller project. I titled mine “CollectioViewFun”. When the project opens up, You’ll want to delete the single view controller from the storyboard and drag a new collection view controller in it’s place. This should look like the following:





Now since our class type has changed from a standard view controller to a collection view controller we’ll want to change the class type in the viewController.h file as well. Go ahead and change the class name from ViewController to CollectionViewController as well. Don’t forget to change all instances of the term “ViewController” in both the .m and .h files:

@interface CollectionViewController : UICollectionViewController <UICollectionViewDataSource>

Since we are going to be using the DataSource protocol of this class I also added the protocol deceleration.

Now select the entire view from the storyboard and change the class to the CollectionViewController class:





Adding A Cell Class

Since each cell will be basically a seperate view, we’ll want to create a class for the cell itself. Go ahead and create a new class of type UICollectionViewCell by clicking the “+” in the bottom left corner and choosing “New File…” . Then Choose the following values in the next two prompts:





Now from the storyboard, Select the cell and change the class from the identity inspector to “Cell” just as you did previously for the CollectionViewController.





Set the Identifier for the cell to “MY_CELL” by selecting the cell from the storyboard and chaing the “Identifier” field under the attributes inspector on the right hand pane.

Select the Collection View Controller window and change the Collection View Cell Size to 150 x 150 points.





Since I’ll be displaying images in the collection view, we’ll want to modify the cell class to have an image view. On the storyboard, Drag an Image View object into the cell and resize to the view to the same size as the Cell.

Now control click and drag from that newly created image view into the Cell.h File and create a new outlet titled imageView:





Alright, Now we’re ready to start modifying the data source methods.

Constructing The Data Source

Choose the CollectionVewController.h file and command click on the protocol decleration “UICollectionViewDataSource” which should bring up the UICollectionView.h file. This file will show you all of the required protocols for this class as well as some optional ones.

For the collectionView there are two required data source protocols and they are “numberOfItemsInSection” and “cellForItemAtIndexPath”

so we’ll go ahead and add those to our CollectinViewController.m class:

#pragma mark - Collection View Data Sources



- ( NSInteger ) collectionView : ( UICollectionView * ) collectionView numberOfItemsInSection : ( NSInteger ) section

{



}



// The cell that is returned must be retrieved from a call to - dequeueReusableCellWithReuseIdentifier:forIndexPath:

- ( UICollectionViewCell * ) collectionView : ( UICollectionView * ) collectionView cellForItemAtIndexPath : ( NSIndexPath * ) indexPath

{



} NSIntegercollectionViewUICollectionViewcollectionView numberOfItemsInSectionNSIntegersectionUICollectionViewCellcollectionViewUICollectionViewcollectionView cellForItemAtIndexPathindexPath

Since I am a bit of a truck enthusiest and I have a bunch of pictures of trucks: I am going to display a few trucks in this collection view controller. Sorry guys, No Chevys.

So lets start off by creating an array of image names in the ViewDidLoad method of the CollectionViewController. Modify the CollectionViewController.h and .m files as follows:

CollectionViewController.h

@interface CollectionViewController : UICollectionViewController & lt;UICollectionViewDataSource,UICollectionViewDelegate & gt;



@property ( strong, nonatomic ) NSArray * truckImages;



@end CollectionViewControllerUICollectionViewControllerlt;UICollectionViewDataSource,UICollectionViewDelegategt;strong, nonatomictruckImages;

CollectionViewController.m viewDidLoad method

- ( void ) viewDidLoad

{

[ super viewDidLoad ] ;

self.truckImages = @ [ @ "silverFord.jpg" , @ "orangeFord.jpg" , @ "yellowFord.jpg" , @ "greenFord.jpg" ] ;

}

Also, we’ll want to import our Cell class into the CollectionViewController class so we can use it. Right after #import “CollecitonViewController.h” in the CollectionViewController.m insert on the next line: #import “Cell.h”

#import "CollectionViewController.h"

#import "Cell.h"

Now we’re ready to edit the Data source methods.

The numberOfItemsInSection data source is pretty easy as it just returns the number of elements in our truck array (In this Case 4). Now we could just put “return 4;” in the method and just be done with it, but that’s not good practice. Instead we’ll return the count of the array. Modify the numberOfItemsInSection as follows:

- ( NSInteger ) collectionView : ( UICollectionView * ) collectionView numberOfItemsInSection : ( NSInteger ) section

{

return self.truckImages.count;

}

the cellForItemAtIndexPath method is bit more tricky, but not too bad. Modify this method as follows:

- ( UICollectionViewCell * ) collectionView : ( UICollectionView * ) collectionView cellForItemAtIndexPath : ( NSIndexPath * ) indexPath

{

Cell * cell = [ collectionView dequeueReusableCellWithReuseIdentifier : @ "MY_CELL" forIndexPath : indexPath ] ;

//cell.imageView.image = [UIImage imageNamed:self.truckImages[0]];

UIImage * truckImage = [ [ UIImage alloc ] init ] ;

truckImage = [ UIImage imageNamed : [ self.truckImages objectAtIndex : indexPath.row ] ] ;

cell.imageView.image = truckImage;

return cell;

} UICollectionViewCellcollectionViewUICollectionViewcollectionView cellForItemAtIndexPathindexPathCellcellcollectionView dequeueReusableCellWithReuseIdentifierforIndexPathindexPathUIImagetruckImageUIImage allocinittruckImageUIImage imageNamedself.truckImages objectAtIndexindexPath.rowcell.imageView.imagetruckImage;cell;

Here we are creating a new Cell object and setting the imageView image to the corresponding truck images at the cell indexpath. Once we have our Cell setup we return it.

At this point if you run the application you should see a grid view with some pictures:





The Last piece of this tutorial is creating a segue to a new View Controller which will give some info about the trucks. First we’ll need to set up the Navigation Controller.

Adding The Navigation Controller

From the storyboard drag a navigation controller from the object library onto the storyboard and delete the tableview controller that is connected to it. Control click from the navigation controller and drag to the collection view controller and choose “Root View Controller” when prompted.

Make sure the incoming arrow which indicates the starting view is on the navigation controller. You can click and drag it over to the the navigation controller if it is not.

Now drag a new view controller onto the storyboard and control click and drag from the cell in document outline to the new view controller. When prompted choose “push” from the modal type drop down.

Next add a new UIImageView object to the new view controller and a label underneath it. Make the Image View 300 x 300 points.

When you are done with these steps your storyboard should look like this:





Create a new class for the new view and give it a subclass of UIViewController. Title the new class ImageDetailViewController and set the class of the new view controller to ImageDetailViewController from the Identity inspector with the view controller selected on the storyboard.

Now create outlets by control clicking and dragging into the ImageDetailViewController.h from the UIImageView and Label we just created. Title these outlets truckImageView and truckDetailLabel.

Now that the Navigation Controller is set up we can implement the prepareForSegue method.

Preparing For The Segue

Now you may have noticed that we are not using the delegate in this instance. The problem with a delegate in this instance is prepareForSegue will be called before the delegate so anything inside the delegate will get ignored. To get around this we’ll add some extra logic to the prepareForSegue method that determines the collectionView indexPath.

First we’ll need to create another array to hold the descriptions for the truck images. Do so by modifying the CollectionViewController.h and m file as follows:

CollectionViewController.h:

@interface CollectionViewController : UICollectionViewController



@property ( strong, nonatomic ) NSArray * truckImages;

@property ( strong,nonatomic ) NSArray * truckDescriptions;



@end CollectionViewControllerUICollectionViewControllerstrong, nonatomictruckImages;strong,nonatomictruckDescriptions;

CollectionViewController.m viewDidLoad method:

- ( void ) viewDidLoad

{

[ super viewDidLoad ] ;

self.truckImages = @ [ @ "silverFord" , @ "orangeFord" , @ "yellowFord" , @ "greenFord" ] ;

self.truckDescriptions = @ [ @ "50's Silver Ford" , @ "50's Orange Ford" , @ "70's Yellow Ford" , @ "50's Green Ford" ] ;

}

To start with, add the following method to the end of the collectionViewController.m file:

#pragma mark - Prepare for Segue

- ( void ) prepareForSegue : ( UIStoryboardSegue * ) segue sender : ( id ) sender

{



}

Before editing the prepareForSegue method we’ll need to import the ImageDetailViewController class into this one as we did fo the Cell class.

#import "CollectionViewController.h"

#import "Cell.h"

#import "ImageDetailViewController.h"

Now we can add code the prepareForSegue method. Go ahead and modify it as follows:

#pragma mark - Prepare for Segue

- ( void ) prepareForSegue : ( UIStoryboardSegue * ) segue sender : ( id ) sender

{

UICollectionViewCell * cell = ( UICollectionViewCell * ) sender;

NSIndexPath * indexPath = [ self.collectionView indexPathForCell : cell ] ;



ImageDetailViewController * imageDetailViewController = ( ImageDetailViewController * ) segue.destinationViewController;

imageDetailViewController.truckImage = [ UIImage imageNamed : [ self.truckImages objectAtIndex : indexPath.row ] ] ;

imageDetailViewController.truckLabelText = [ self.truckDescriptions objectAtIndex : indexPath.row ] ;

} prepareForSegueUIStoryboardSeguesegue sendersenderUICollectionViewCellcellUICollectionViewCellsender;indexPathself.collectionView indexPathForCellcellImageDetailViewControllerimageDetailViewControllerImageDetailViewControllersegue.destinationViewController;imageDetailViewController.truckImageUIImage imageNamedself.truckImages objectAtIndexindexPath.rowimageDetailViewController.truckLabelTextself.truckDescriptions objectAtIndexindexPath.row

This code does a few things. First we create an instance of the UICollectionViewCell class to get the sender. Using that, we create an NSIndexPath object. The indexPath will be what we’ll use to know which cell was selected.

Then we create an instance of our ImageDetailViewController class and set the image and label text values using the indexPath to find values in the truckImages array and truckDescriptions array.

Now this code won’t work yet until we set some properties in the ImageDetailViewController class. Edit the ImageDetailViewController.h file as follows:

@interface ImageDetailViewController : UIViewController



@property ( strong, nonatomic ) IBOutlet UIImageView * truckImageView;

@property ( strong, nonatomic ) IBOutlet UILabel * truckDetailLabel;

@property ( strong, nonatomic ) UIImage * truckImage;

@property ( strong, nonatomic ) NSString * truckLabelText;



@end ImageDetailViewControllerUIViewControllerstrong, nonatomicIBOutlet UIImageViewtruckImageView;strong, nonatomicIBOutlet UILabeltruckDetailLabel;strong, nonatomicUIImagetruckImage;strong, nonatomictruckLabelText;

Then update the ImageDetailViewController.m viewDidLoad method as follows:

- ( void ) viewDidLoad

{

[ super viewDidLoad ] ;

self.truckImageView.image = self.truckImage;

self.truckDetailLabel.text = self.truckLabelText;

}

This Step is needed because we can’t directly write to the UIImage and UILabel properties.

Now Everything should work! Run it and press one of the collection view icons and you should see a screen that looks like this.

I know this tutorial was a bit long winded, but I wanted to show the use of the navigation controller in this recipe as well. Setting up the navigation portion of a UICollectionViewController is close to the same process we would use to add a navigation controller to a UITableViewController.

Another Thing to note is by choosing the UICollectionViewController object in the beginning automatically connected our datasource and delegate connections for us. If you have implemented all of this code and nothing is showing up, chances are you need to make these connections.

That’s it! Hope you enjoyed this!