Handling Single and Multiple Selection in Collection View

27 Flares 27 Flares ×

In the past two tutorials, we covered the basics of UICollectionView and header/footer customization. You should already know how to display items using UICollectionView. However, we haven’t covered how to interact with the collection view cell.

As mentioned before, the Collection View works in a way pretty much like Table View. But to give you a better idea, we’ll show how to interact with the collection items such as the ways to handle single and multiple item selection. To provide you with a working example of how the item selection works, we’ll continue to improve the Recipe app. Here are what we’re going to implement:

  1. To demonstrate how you can handle single selection, we’ll improve the Recipe app. When user taps a recipe photo, the app will bring up a modal view and display the photo in larger size.
  2. We’ll also implement Facebook sharing in the app in order to show you multiple item selection. Users are allowed to select multiple photos and share them on Facebook.

Recipe App Multiple Selection

The interface of the app is very simple and will not win any design award. However, it’ll give you an idea of how to interact with collection view. To spare you from setting up the Xcode project, you can download this Xcode template. Please note that the Xcode project is created using Xcode 4.6 and tested on iOS 6. If you find any problem opening/compiling the project, please upgrade your Xcode to the latest version.

Handling Single Selection

First, we’ll improve the Recipe app to handle single selection. When user taps any of the recipe photo, the app will bring up a modal view to display the photo in higher resolution.

Designing the User Interface

To begin, let’s design the view controller for displaying the recipe photo. Go to Storyboard, drag a View Controller from Object library. Then add an Image View to it and set the width and height to 320 and 200 respectively. Lastly, add a navigation bar to the top of view and assign it with a Bar Button Item. Set the name of the button item as “Close”. Your View Controller should look similar to the below one:

Designing the Modal View Controller

Designing the Modal View Controller

As we want to display the view controller when user taps any of the recipe photo in the collection view, we’ll connect the collection view with the view controller using a segue. Press the control button, click on the “Recipe View Cell” and drag it towards the View Controller. Select “modal” for the style and set the segue identifier to “showRecipePhoto”.

Segue Connection

Segue Connection

If you compile and run the app, you’ll end up with an empty view when selecting any of the recipe photo. As we haven’t provided the code implementation, the modal view controller has no idea of the selected recipe photo. So, create a new class (as a subclass of UIViewController) and name it as “RecipeViewController”. In Storyboard, select the view controller we just created and set the custom class to RecipeViewController.

Set the custom class as RecipeViewController

Set the custom class as RecipeViewController

Next, we’ll establish a connection between the image view and the RecipeViewController.h. Press and hold the control key, click the image view and drag it towards the “RecipeViewController.h”. Name the variable as “recipeImageView”. Repeat the same procedure and establish a connection with “action” type for the close button.

Establish Variable Connection

Establish Variable Connection

Into the Code

In order to let other controllers pass the image name, we’ll also add a “recipeImageName” property for this purpose. Here is the code excerpt of the RecipeViewController.h:

1
2
3
4
5
6
7
8
@interface RecipeViewController : UIViewController

@property (weak, nonatomic) IBOutlet UIImageView *recipeImageView;
@property (weak, nonatomic) NSString *recipeImageName;

- (IBAction)close:(id)sender;

@end

When displayed, the RecipeViewController will load the specified recipe image in the image view. So in the RecipeViewController.m, change the viewDidLoad method to the following:

1
2
3
4
5
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.recipeImageView.image = [UIImage imageNamed:self.recipeImageName];
}

Okay, we have completed the implementation of RecipeViewController. But there is still one thing left. How can we identify the selected item of the collection view and pass the image name to the RecipeViewController? We’ll implement the prepareForSegue:sender: method in RecipeCollectionViewController, which is the source view controller of the segue. Select the “RecipeBookViewController.m” and add the following code:

1
2
3
4
5
6
7
8
9
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"showRecipePhoto"]) {
        NSArray *indexPaths = [self.collectionView indexPathsForSelectedItems];
        RecipeViewController *destViewController = segue.destinationViewController;
        NSIndexPath *indexPath = [indexPaths objectAtIndex:0];
        destViewController.recipeImageName = [recipeImages[indexPath.section] objectAtIndex:indexPath.row];
        [self.collectionView deselectItemAtIndexPath:indexPath animated:NO];
    }
}

Note: If you forget how segue works, it is highly recommended to check out our segue tutorial before proceeding.

The UICollectionView class provides the indexPathsForSelectedItems method that returns the index paths for the selected items. You may wonder why there are multiple index paths returned. The reason is that UICollectionView supports multiple selection that we’ll cover in the next section. Each of the index path corresponds to a particular selected item. As for this example, we only have single item selection. Therefore, we’ll pick the first index path and retrieve the selected image (Line 5-6).

In collection view, when user taps on a collection cell, the cell changes to the highlighted state and then to the selected state. Therefore, we add a line of code to deselect the selected item once the image is displayed in the modal view controller.

Don’t forget to add the import statement at the very beginning of RecipeCollectionViewController.m, otherwise, your code won’t compile properly:

1
#import "RecipeViewController.h"

Now, let’s build and run the app. After the app is launched, tap any of the recipe and you should see a modal view showing the selected recipe image.

Recipe App - Single Selection

Recipe App – Single Selection

If you’ve tried to close the modal view, it doesn’t work properly. Obviously, we leave out the implementation of the “close” method in RecipeViewController. Simply edit the following method in the RecipeViewController.m and add a line of code:

1
2
3
- (IBAction)close:(id)sender {
    [self dismissViewControllerAnimated:YES completion:NULL];
}

This dismissViewControllerAnimated method tells the view controller to dismiss. Compile and run the app again. The close button should now work.

Handling Multiple Selection

UICollectionView supports both single and multiple selection. However, user is allowed to select single item by default. The allowsMultipleSelection property of UICollectionView class controls whether multiple items can be selected simultaneously. To enable multiple selection, the trick is to set the property to YES.

To give you a better idea of how multiple selection works, we’ll continue to tweak the Recipe app. User are allowed to select multiple recipes and share them on Facebook in the following ways:

  1. User taps the “Share” button in the navigation bar to start the sharing process and the button title is automatically changed to “Upload”.
  2. User selects the recipe photos to share.
  3. After the selection, user taps the “Upload” button. The app will bring up the Facebook dialog to share the photos on Facebook.

Note: We assume that you’re familiar with the implementation of Facebook sharing. If you’re new to it, we recommend you to check out the Facebook sharing tutorial before moving on.

Designing the User Interface

We’ll first add the “Share” button in the navigation bar. Go to Storyboard, drag a Bar Button Item from Object library and add it to the navigation bar of Recipe Collection View Controller.

UICollectionView Multiple Selection Share Button

Adding the Share Button

Like before, establish a connection between the Share button and RecipeCollectionViewController.h. Name the property as “shareButton”. We also add an action method that is called when the Share button is tapped.

UICollectionView Share Button IBAction

Establish Connections with the Share Button

Your code of RecipeCollectionViewController.h should look like this:

1
2
3
4
5
@interface RecipeCollectionViewController : UICollectionViewController
@property (weak, nonatomic) IBOutlet UIBarButtonItem *shareButton;
- (IBAction)shareButtonTouched:(id)sender;

@end

Into the Code

The Recipe app now offers two modes: single selection and multiple selection. When user taps the “Share” button, the app will go into the multiple selection mode that allows user to select multiple photos for sharing. To support the multiple selection mode, we’ll add two variables to the RecipeCollectionViewController.m:

  • shareEnabled – it’s a boolean variable to indicate the selection mode. If it’s set to YES, it indicates the “Share” button is tapped and multiple selection is enabled.
  • selectedRecipes – it’s an array to store the selected recipes

Your code should look like below:

1
2
3
4
5
@interface RecipeCollectionViewController () {
    NSArray *recipeImages;
    BOOL shareEnabled;
    NSMutableArray *selectedRecipes;
}

In addition, add the following line of code in viewDidLoad method to initialize the array:

1
    selectedRecipes = [NSMutableArray array];

Managing Item Selection and Deselection

The UICollectionViewDelegate protocol defines methods that allow you to manage the selection and highlighting of items in a collection view. When user selects an item, the collectionView:didSelectItemAtIndexPath: method is invoked. We’ll implement this method and add the selected items into the selectedRecipes array. Place the following code before the “@end” statement:

1
2
3
4
5
6
7
8
9
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    if (shareEnabled) {
        // Determine the selected items by using the indexPath
        NSString *selectedRecipe = [recipeImages[indexPath.section] objectAtIndex:indexPath.row];
        // Add the selected item into the array
        [selectedRecipes addObject:selectedRecipe];
    }
}

The UICollectionViewCell class provides a property to set the background view of a selected item. To indicate a selected item, we’ll change the background image of collection cell to a different image (i.e. photo-frame-selected.png). Simply place the following code in the collectionView:cellForItemAtIndexPath: method:

1
    cell.selectedBackgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"photo-frame-selected.png"]];
Collection View Cell Selected

Change the background image for selected cell

Not only we have to handle item selection, we also need to cater for deselection. For any reasons, user may deselect an item from the collection view. When an item is deselected, it should be removed from the selectedRecipes array. So place the following code after the above method:

1
2
3
4
5
6
7
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
    if (shareEnabled) {
        NSString *deSelectedRecipe = [recipeImages[indexPath.section] objectAtIndex:indexPath.row];
        [selectedRecipes removeObject:deSelectedRecipe];
    }
}

Next, we’ll move onto the implementation of shareButtonTouched: method, which is called when user taps the Share button. Edit the method with the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
- (IBAction)shareButtonTouched:(id)sender {
    if (shareEnabled) {
       
        // Post selected photos to Facebook
        if ([selectedRecipes count] > 0) {
            if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
                SLComposeViewController *controller = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
               
                [controller setInitialText:@"Check out my recipes!"];
                for (NSString *recipePhoto in selectedRecipes) {
                    [controller addImage:[UIImage imageNamed:recipePhoto]];
                }
               
                [self presentViewController:controller animated:YES completion:Nil];
            }
        }
       
        // Deselect all selected items
        for(NSIndexPath *indexPath in self.collectionView.indexPathsForSelectedItems) {
            [self.collectionView deselectItemAtIndexPath:indexPath animated:NO];
        }
       
        // Remove all items from selectedRecipes array
        [selectedRecipes removeAllObjects];
       
        // Change the sharing mode to NO
        shareEnabled = NO;
        self.collectionView.allowsMultipleSelection = NO;
        self.shareButton.title = @"Share";
        [self.shareButton setStyle:UIBarButtonItemStylePlain];
       
    } else {
       
        // Change shareEnabled to YES and change the button text to DONE
        shareEnabled = YES;
        self.collectionView.allowsMultipleSelection = YES;
        self.shareButton.title = @"Upload";
        [self.shareButton setStyle:UIBarButtonItemStyleDone];
       
    }
}

To help you understand the above, let’s take a look at the code line by line:

Line 35-38: If sharing mode is originally disabled, we’ll put the app into sharing mode and enables multiple selection. At the same time, we change the title of button to “Upload”.

Line 5-16: In sharing mode, after user taps the “Upload” button, we’ll bring up Facebook composer. The SLComposeViewController comes with some built-in methods to allow you easily upload multiple photos. We simply use the “addImage” method to attach the images.

Line 19-24: After uploading the photos to Facebook, we deselect the selected items and remove them from the selectedRecipes array.

Line 27-30: Lastly, we switch back to the single selection mode.

As “SLComposeViewController” is a class provided by the Social framework, remember to import the Social.h file at the very top of the “RecipeCollectionViewController.m”:

1
#import <Social/Social.h>

By default, the Social framework is not included in the Xcode project. To compile the app properly, add the “Social.framework” in the project. In the Project Navigator, select the “CollectionViewDemo” project. In the Content Area, select “CollectionViewDemo” under Targets and click “Build Phases”. Expand “Link Binary with Libraries” and click the “+” button to add the “Social.framework”.

Collection View Adds Social Framework

Add Social Framework

We’re almost done. However, if you run the app now, you’ll end up with a bug. After switching to the sharing mode, the modal view still appears when you select any of the recipe photos. This is not what we expect. The reason is that the segue is invoked every time when the collection cell is tapped. With the release of iOS 6, you can specify if you want the segue to be triggered by using a new method called shouldPerformSegueWithIdentifier. Obviously, we only want to trigger the segue when it’s in single selection mode. Place the following code before the “@end” statement:

1
2
3
4
5
6
7
8
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
    if (shareEnabled) {
        return NO;
    } else {
        return YES;
    }
}

Great! Now compile and run the app again. Tap the Share button, select a few recipe photos and tap the Upload button to share them over Facebook.

Recipe Collection App Facebook Deliverable

Recipe App – Multiple Selection

What’s Coming Next

I hope you love this tutorial. For your complete reference, you can download the complete Xcode project from here. After going through the series of Collection View tutorials, you should know how to arrange data items in grid view, add header/footer view and interact with the collection cells.

In the coming tutorial, we’ll look into something new and show you how to manage audio in your iOS app. As always, if you have any problem or suggestions about the tutorial, leave us comment and share your thought.

You May Like These:

Get Free Chapters of Our Swift Book

Beginning iOS 8 Programming with SwiftIf you want to create an app but don't know where to begin, this book covers the whole aspect of Swift programming and iOS 8 development and shows you every step from an idea to a real app on App Store. This book features a lot of hands-on exercises and projects. You will first create a simple app, then prototype an app idea, and later add some features to it in each chapter, until a real app is built. Want to learn more? Check it out here and get three free chapters.


  • rufusmi

    I just want to say thank you for all of your work you put into these app development tutorials and setting up this website. Thanks for all of your hard work simon!

  • kevin chen

    Thanks, It is very good. Hope for next tutorial.

    • DoctorCobweb

      just make a copy of the photo-fram.png file, edit it using GIMP (say), add the coloured border then export it to “photo-frame-selected.png”. if the alpha channel is set it will screw up your UI when running the app. i deleted the alpha channel on my edit because for some reason it became non zero. hope this helps.

  • Podster

    I would love to know how to replace the photo album name from iOS Photos to my App Name…

  • Chih-han

    You lost photo-frame-selected.png in your zip file.

  • bagusflyer

    Great tutorial. But you missed one part which you mentioned you in your first tutorial about UICollectionView. Which is DecorationView. Are you going to discuss this in your following tutorial? Thanks

  • Charles

    when i run it, it terminates due to uncaught exception…

    2013-04-10 22:02:53.742 CollectionViewDemo[1505:c07] *** Terminating app due to uncaught exception ‘NSUnknownKeyException’, reason: ‘[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key shareButton.’

    *** First throw call stack:

    (0x234e012 0x11b9e7e 0x23d6fb1 0xc65e41 0xbe75f8 0xbe70e7 0xc11b58 0x31b019 0x11cd663 0x234945a 0x319b1c 0x54554a 0x5456c3 0xfd71e 0xfd9a2 0xfc876 0x10dcb5 0x10ebeb 0x100698 0x28a8df9 0x28a8ad0 0x22c3bf5 0x22c3962 0x22f4bb6 0x22f3f44 0x22f3e1b 0xfc17a 0xfdffc 0x1f0d 0x1e35)

    libc++abi.dylib: terminate called throwing an exception

    (lldb)

    I tried work through the tutorial and got this problem after implementing the prepareforsegue above.
    So i download the complete code package and try to run, same error… :(
    any advise?

    • John R Dempsey

      I get the same error

      • mikkkk

        Sounds like there are some invalid connections between shareButton and RecipeCollectionViewController.h.

        Check that the shareButton outlet and action are connected properly i.e. the button’s IBOutlet and IBAction method to the RecipeCollectionViewController.h. You should dismiss any other connections for the button to make it work in this tutorial.

  • Tanvi

    Hey, thanks for such a nice tutorials. I have one query on header view. I
    have multiple sections in my Data Grid. How can i fix my header for
    multiple sections. Means, i want header should not move while scrolling
    data grid. Can you help me out?

    • SpokaneDude

      Tanvi: did you get this resolved? I need something similar to this: the left column and top row have to scroll with the remainder of the cells, like you can do with any spreadsheet program (lock row or column).

  • Pingback: UICollectionView Basics | rhezjovovich

  • Nic

    Thanks for your tutorial. I’ve learnt a lot.
    It would be great if you have a sticky header ( always on top in one section ) in collection view.

  • k0e3

    How come before we used a button for cancel and save, but now it’s a bar button item?

    • k0e3

      Never mind, I must be going insane.

  • PeterOhalo

    Thanks its works

  • Birdy Birdas

    i cannot segue to Display an image to view on Xcode5

  • b

    Excellent series of tutorials. Got me up and running with collection views quickly. Thanks.

  • Mohamed

    great tutorial but if i replace the collection view by scrollview so i need to when user select the image from scroll controller send the image to another view controller; so please help me

  • Mạnh Hiền Lành

    it’s can’t share on Facebook , i tried run your project,why is???

  • yolou

    How to put the navigation bar above the uicollection header view, the header view is occupying the place where the navigation bar should be,

    • Tiago De Barros Hillesheim

      Probably you don’t have a Nav controller. Select the Collection View Controller and then choose “Editor” > “Embed In” > “Navigation Controller” … the view collection should go down a bit.

  • sankar ram

    Hello ,
    I want to know how to select the cell in the UICollection View, Here the Tutorial is Fine but I didn’t get the Image that Background Selected… from your source code itself help me in this!!!!

    • Tiago De Barros Hillesheim

      This image is not in the zip, you have to create it. Open the original frame in Photoshop, change the color or something and save it as “photo-frame-selected.png”. You must import the file to the project, even if it’s already in the folder.

  • Hala Salih

    I followed this tutorial till the handling multiple selection part, whenever I click and image, the app crashes and I get a memory warning, after some googling, I replaced the method imagenamed with imageWithContentsOfFile and it still crashes .. (using xcode 5.0.2 and iOS 7.0.4)

    • Hala Salih

      Found the solution .. replace the line I mentioned above with this:

      destViewController.recipeImageName = recipeImages[indexPath.row]

  • Spehler Rémy

    Hi
    Thank you very much for this great tutorial!!! It works perfectly.
    One question please: I want to select one picture, the symbol of one area, and after this choice N°1, select one catégorie with PickerView, choice N°2, but Choice N°2 must redirect on the webpage (Choice N°1 + ChoiceN°2).
    Do you think it’s possible?
    Thank you for your help.
    Gracefully
    Rémy

  • Richard Lewison

    Great set of tutorials. There are some differences when developing for iOS7 that you may want to mention.

  • Betoneira

    Nice Tutorial, many thanks for this. I am wondering how to load images from web server, this means the images are stored outside the app. The code i use is:

    NSURL * recipePhotosFile = [NSURL URLWithString:@"http://www.server.com/recipePhotos.plist"];
    recipePhotos= [[NSDictionary alloc] initWithContentsOfURL:recipePhotosFile];
    NSArray *mainDishImages = [recipePhotos objectForKey:@"Fotos"];

    With this code the thumbs are populated with the images at the plist, but i need to have them all inside app and i need them outside to be able to add more images.

    Thank you in advance

  • venkatinjarapu

    It was very use full for me thanks man

27 Flares Twitter 16 Facebook 0 Google+ 7 LinkedIn 4 27 Flares ×