Wednesday, March 21, 2012

Handling multiple selection in iPhone TableView

- Rashid Khaleefa
Its a common practice to list down the data or items in any mobile phone. The display of contact list is a very common example in any mobile phone where you see a list of contacts saved. Even though the brand, the OS or the model differs, when it comes to bulk of data to display either a listview control or any tableview alternative controls are used.
In iPhone items can be displayed using the UITableview control. I came across using this control in my iPhone app. It was quiet easy to get started with displaying a list of data from an array. I just had to use the UITableview control along with its delegates to handle the display. It is much cool to use three functions as below to display the items. Here I have an array of dictionaries to list out in the tableview.

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//Return the number of rows in the section.
return [tableList count];
}

And cellForRowAtIndexPath function gets called once for each row. This is where we define what content to display in a given row or cell. We assign the values to each cell labels. I have used a custom cell designed with three labels and an imageview separately and values are assigned to the corresponding controls in each cell.

-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
 static NSString *CellID = @"CustomCell";
 CustomCellController *cell = (CustomCellController*)[tableView  
 dequeueReusableCellWithIdentifier:CellID];
 if (cell == nil)
 {
  NSArray *topLevelObjects = [[NSBundle mainBundle]   
  loadNibNamed:@"CustomCellController" owner:nil options:nil];
 for(id currentObject in topLevelObjects)
 {
  if([currentObject isKindOfClass:[CustomCellController class]])
  {
  cell = (CustomCellController *)currentObject;
  break;
  }
 }
}
//tableList is an array on dictionary elements.
NSDictionary *item = (NSDictionary *)[tableList objectAtIndex:indexPath.row];
[[[cell Name] setText:[UserUtils convertSize:[item objectForKey:@"ImageName"]]];
[[cell Size] setText:[item objectForKey:@"Size"]];
[[cell Date] setText:[item objectForKey:@"Date"]];
[[cell imageView] setImage:[UIImage imageNamed:@"image.png"]];
return cell;
}

But I was stuck when it came to select multiple items from the table. I quiet easily managed to select a singe item from the list using the didSelectRowAtIndexPath function. But When it came to multiple selection I started breaking my head over. This made me google and got some solutions. But never stopped me googling more because most of the solution worked fine when there was only a page of data to display, where for me it was a list of twenty items.

The first thing I had to do was to select and deselect items in table which was identifiable by a check mark indication over the selected cell. Then I wanted to retrieve the corresponding dictionary of the selected items.
The issue I faced trying to select multiple items was that when I select fist item in the table of a particular page, the corresponding first item of all page was selected and so I was not able to differentiate the item list that was actually selected. And also to select and unselect multiple items from table took me some time to work it fine.

This is how I came up with the solution

-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
 NSMutableDictionary *rowDict = [tableList objectAtIndex:  
 [indexPath row]];
 NSString *SelectedState = (NSString*)[rowDict 
 objectForKey:@"objSelected"];
 if([SelectedState isEqualToString: @"YES"])
 {
  [rowDict setObject:@"NO" forKey:@"objSelected"];
  [tableView cellForRowAtIndexPath:indexPath].accessoryType
  UITableViewCellAccessoryNone;
 }
 else
 {
  [rowDict setObject:@"YES" forKey:@"objSelected"];
  [tableView cellForRowAtIndexPath:indexPath].accessoryType
  UITableViewCellAccessoryCheckmark;
 }
 [tableView reloadData];
 [tableView setNeedsDisplay];
}

- (void)tableView:(UITableView *)tableView willDisplayCell:   
  (UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath
  *)indexPath
{
 NSDictionary *item = (NSDictionary *)[tableList  
 objectAtIndex:indexPath.row];
 NSString *SelectedState = (NSString*)[item 
 objectForKey:@"objSelected"];
 if([SelectedState isEqualToString: @"YES"])
 cell.accessoryType = UITableViewCellAccessoryCheckmark;
 else
 cell.accessoryType = UITableViewCellAccessoryNone;
}

Here, in didSelectRowAtIndexPath I have first retrieved the dictionary values at the particular index of selection and add one more value based on selection (YES when selected and NO when deselected) for key objectSelected and thereby placing a check mark by setting the cell accessoryType to UITableViewCellAccessoryCheckmark. This will obviously reflect the tablelist array as it is declared globally. So to make it simple the refreshed tablelist will have an additional key value pair which differentiates the selected items from the deselected one.

There will be n number of solutions for any issue of this kind. I would say this is also a way how I fixed the issue I faced. I hope this might be a useful post for any one working with UITableview in iPhone.


2 comments:

hard drive data recovery cost said...

Every phone have different features rely on manufacturer and brand, OS also depend upon it. It is nice share , i will refer it to my friend to examine it that what can be done with it.

Anonymous said...

Do you have working sample code?