The Collection View: Part 6 of 6

This is the final tutorial in the Collection View series and in it you’ll learn how to enable the app user to select multiple flashcard photos (Collection View Cell items), which the app highlights. Enable the app user to send the flashcard photos he selected to one or more friends.

download-excodeprojThe first thing I want you to do is download this version of the GreekAlphabets application; it’s an alternate version of the GreekAlphabets project we developed in part 5 of the the Collection View tutorial. In a nutshell I made these modifications to the project.

I replaced the storyboard’s Collection View Controller with a View Controller and a Toolbar as shown in Figure A below. I declared and connected an outlet property for the Collection View, the ToolBar, and the Toolbar’s Share button. I declared and connected an action method for the Toolbar’s button. In Interface Builder, I connected the Collection View’s dataSource and delegate outlet to the Master View Controller. Finally, in Interface Builder’s Size Inspector, I set properties for the Collection View Size item and the View item-see the Utility panel in Figure A below.

Now, when you run the application, the the Master View Controller’s view will look like Figure B. Further more; when you click the Toolbar’s Share button, a message is shown in the Debugger window-see the bottom of Figure A.

cvappver2-figa cvappver2-figb
Figure A: The app’s view in Interface Builder Figure B: The app’s view in the iPad Simulator

The GreekAlphabets Application Use Case Scenarios

Here are use case scenarios for the new version of the GreekAlphabets application.

User Action System Response
The user taps the Toolbar’s Share button. The app respond to the user’s action by doing the following tasks:

  • Put the Collection View in sharing mode; thus allowing the app user to select multiple Collection View Cells (flashcard images).
  • Change the Share button’s title property to Done.

cvappver2-figb

The user taps the Collection View Cells. The system respond to the user’s action by checking to see if the Collection View is in sharing mode. If it is, the system does the following:

  • Highlights the Collection View Cells the user tapped.
  • Add the flashcard photos (Collection View Cell items) the user selected in an array called selectedFlashcards.

cvappver2-figd

The user taps the Toolbar’s Done button. The system respond to the user’s action by doing the following tasks:

  • Take the Collection View out of sharing mode; thus allowing the app user to select only one Collection View Cell item at a time.
  • Change the Toolbar button’s title property back to Share.
  • Call the showMailComposerAndSend method, only if the selectedFlashcards array contain one or more objects (flashcard photos).
  • Unhighlight the Collection View Cells the user previously selected.
  • Remove all objects from the selectedFlashcards array.

cvappver2-figc

Note:

The showMailComposerAndSend method’s job is two fold:

  1. Show the MailCompose’s view-see the image in the left column of this table.
  2. Configure two properties (Subject and MessageBody) of the email.

As you can see in the image in the left column of this table, the email’s MessageBody consist of a two-column table of flashcard photos and the default text message the system added below the table. The user will have to enter one or more recipient’s email addresses in the “To:” field. Optionally, the user can enter one or more email addresses in the “Cc/Bcc:” field.

The user taps the MailComposer’s Send button. The system check to see if the MailComposer object can send mail; if so, the system sends the email. If the system’s MailComposer object is unable to send mail; the system display an Alert View message.
The user taps the MailComposer’s Cancel button. The system responds to the users’s action by dismissing the MailComposer view.

What we have to do now is implement the “System Tasks” listed in above Use Case Scenarios; thus fulfilling our objects; which are to enable the app user to select multiple flashcard photos (Collection View Cell items), which the app highlights. Enable the app user to send the flashcard photos he selected to one or more friends.

Add Code in the MasterViewController Class Files

Start by clicking the MasterViewController.h file, then declare this property variables. The first variable is for storing the Collection View items (flashcard photos) the user selects from the Collection View. The second variable is for determining whether the Collection View is in sharing mode or not.

@property(nonatomic, strong) NSMutableArray *selectedFlashcards;
@property(nonatomic, readwrite) BOOL sharingEnabled;

Next, add this import line in the MasterViewController.h file.

#import <MessageUI/MessageUI.h>

What you have to do now is add the MessageUI.framework in the projects so we can use the MFMailComposeViewController class and its delegate method, mailComposeController:.

Click the project’s root folder, then the Build Phase item. Expand the Link Binary With Libraries item and click the + button. When you see this window:

cvappver2-fige

Enter mes in the search box. Select the MessageUI.framework, then click the Add button.

Return to the MasterViewController.m file and modify the viewDidLoad method’s code to what’s shown below.

- (void)viewDidLoad
{
  [super viewDidLoad];

  // Register our RecipeCell class with the Collection View so we can use its properties and methods
  self.collectionView registerClass:[FlashcardCell class] forCellWithReuseIdentifier:@"Cell"];

  // Set the Collection View to display a background image
  self.collectionView.backgroundView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"subtle_white_feathers"]];

  // Create and initialize two arrays with image names
  NSArray *flashcardSet1 = @[@"alpha-front",
  @"vita-front",
  @"gamma-front",
  @"thelda-front",
  @"epsilon-front",
  @"zita-front"];

  NSArray *flashcardSet2 = @[@"ita-front",
  @"theta-front",
  @"iota-front",
  @"kappa-front",
  @"lamdha-front",
  @"mi-front"];

  // Add above arrays as elements of the flashcardImagesFront array
  self.flashcardImagesFront = @[flashcardSet1,flashcardSet2];

  // Initialize two property variables
  self.selectedFlashcards = [@[] mutableCopy];
  self.sharingEnabled = NO;
}

Ok, modify these data source methods of the Collection View.

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
  if (self.sharingEnabled) {
    NSString *imageName = [_flashcardImagesFront[indexPath.section] objectAtIndex:indexPath.row];
    [self.selectedFlashcards addObject:imageName];
  }
}

- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
  if (self.sharingEnabled) {
    NSString *imageName = [_flashcardImagesFront[indexPath.section] objectAtIndex:indexPath.row];
    [self.selectedFlashcards removeObject:imageName];
  }
}

As you already know above methods are fired when the user select and unselect a Collection View Cell. Code you entered in the collectionView didSelectItemAtIndexPath: method check to see if the Collection View is in sharing mode. If it is, then code in the if() block add flashcard photos in the selectedFlashcards array. Code you entered in the collectionView didDeselectItemAtIndexPath: method also check to see if the Collection View is in sharing mode. If it is, then code in the if() block remove flashcard photos from the selectedFlashcards array.

Now, when the user select a Collection View Cell, the system should highlight it. You’ll have to click the FlashcardCell.m file, then add highlighted statements in the initWithFrame: method.

#import "FlashcardCell.h"

@implementation FlashcardCell

// This method is fired when an instance of this class is created
- (id)initWithFrame:(CGRect)frame
{
  self = [super initWithFrame:frame];
  if (self) {
    // Create a view object and add it in the Collection View's contentView
    UIView *insetView = [[UIView alloc] initWithFrame:
    CGRectInset(self.bounds, self.bounds.size.width/8, self.bounds.size.height/8)];
    [self.contentView addSubview:insetView];

    // Create an imageView control, customize its appearance, then add it in the subview, insertView
    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, insetView.frame.size.width,
    insetView.frame.size.height)];
    self.imageView.backgroundColor = [UIColor clearColor];
    self.imageView.clipsToBounds = YES;
    self.imageView.layer.opacity = 1.0;
    self.imageView.layer.borderColor = [UIColor grayColor].CGColor;
    self.imageView.layer.borderWidth = 4.0;
    self.imageView.userInteractionEnabled = YES;
    [insetView addSubview:self.imageView];

    // Set the selected Collection View Cell's background color
    UIView *bgView = [[UIView alloc] initWithFrame:self.backgroundView.frame];
    bgView.backgroundColor = [UIColor colorWithRed:255/255.0 green:255/255.0 blue:153/255.0 alpha:1];
    bgView.layer.borderColor = [[UIColor clearColor] CGColor];
    bgView.layer.borderWidth = 4;
    self.selectedBackgroundView = bgView;
  }

  // Return the newly created Collection View Cell to its reciever, which is a Collection View
  return self;
}

Here’s the code to add in the Toolbar’s shareButtonTapped: method.

- (IBAction)shareButtonTapped:(id)sender
{
  if (!self.sharingEnabled) {
    // The user tapped the Share button
    self.sharingEnabled = YES;
    self.collectionView.allowsMultipleSelection = YES;
    [self.shareButton setTitle:@"Done"];
  } else {
    // The the user tapped the Done button
    self.sharingEnabled = NO;
    [self.shareButton setTitle:@"Share"];
    self.collectionView.allowsMultipleSelection = NO;

    if ([self.selectedFlashcards count] > 0) {
      // The user selected 1 or more cells, so call the showMailComposerAndSendEmail method
      [self showMailComposerAndSendEmail];
    }

    for(NSIndexPath *indexPath in self.collectionView.indexPathsForSelectedItems) {
      // Deselect previously selected Collected View Cells
      [self.collectionView deselectItemAtIndexPath:indexPath animated:NO];
    }

    // Empty out the selectedFlashcards array
    [self.selectedFlashcards removeAllObjects];
  }
}

When you launch the application and click the Toolbar’s Share button; the first if() block’s statements are executed. However, when you click the Toolbar’s Done button, the else block’s code are executed.

Finally, here’s the code to implement the showMailComposerAndSendEmail method and to dismiss the Mailer’s view.

cvappver2-figf

// This method dismiss the MailerComposeViewController's view
- (void)mailComposeController: (MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
  [controller dismissViewControllerAnimated:YES completion:nil];
}

The showMailComposerAndSendEmail method’s job is to check to see if the MFMailComposeViewController can send the email; if so, code within the first if() block does the following:

  • Create and initialize an instance of the MFMailComposeViewController class, called mailer.
  • Set four properties of the mailer object (mailComposeDelegate, Subject, MessageBody, isHTML).
  • Display the flashcard photos the user selected in a two-column table.
  • Display the Mailer’s view in the iPad Simulator.

If the MFMailComposeViewController cannot send the email; code within the else block inform the user via an Alert View.

Test The MasterViewController Class Code

Go ahead and run the application so you can test the Toolbar’s shareButtonTapped: method’s code. Once the application’s view is loaded in the iPad Simulator’s window, click the Share button to put the Collection View in sharing mode. Next, click two or more Collection View Cells; as you can see, they are highlighted. Next, click the Done button. The app will display the MFMailComposeViewController’s view in the iPad Simulator’s window. Click the Cancel button, then the Delete Draft menu item. The App dismiss the MFMailComposeViewController’s view. By the way, you need a real iDevice to test the MailerComposeViewController’s Send button.

That’s it, you’ve reach the end of the Collection View tutorial series.