-
Notifications
You must be signed in to change notification settings - Fork 1
DD 4.3. Creating Custom Table View Cell Accessories
The accessories provided to you by the iOS SDK are not sufficient, and you would like to create your own accessories.
Assign an instance of the UIView class to the accessoryView property of any instance of the UITableViewCell class:
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell* cell = nil; cell = [tableView dequeueReusableCellWithIdentifier:MyCellIdentifier forIndexPath:indexPath]; cell.textLabel.text = [NSString stringWithFormat:@"Section %ld, Cell %ld", (long)indexPath.section, (long)indexPath.row]; UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; button.frame = CGRectMake(0.0f, 0.0f, 150.0f, 25.0f); [button setTitle:@"Expand" forState:UIControlStateNormal]; [button addTarget:self action:@selector(performExpand:) forControlEvents:UIControlEventTouchUpInside]; cell.accessoryView = button; return cell; }
As you can see, this code uses the performExpand: method as the selector for each button. Here is the definition of this method:
- (void) performExpand:(UIButton *)paramSender{ /* Handle the tap event of the button */ }
An object of type UITableViewCell retains a property named accessoryView. This is the view you can assign a value to if you are not completely happy with the built-in iOS SDK table view cell accessories. After this property is set, Cocoa Touch will ignore the value of the accessoryType property and will use the view assigned to the accessory View property as the accessory assigned to the cell.
The code listed in this recipe’s Solution creates buttons for all the cells populated into the table view. When a button is pressed in any cell, the performExpand: method gets called, and if you are like me, you have probably already started thinking about how you can determine which cell the sender button belongs to. So now we have to somehow link our buttons with the cells to which they belong.
One way to handle this situation is to take advantage of the tag property of the button instance. The tag property is a simple integer that people usually use to associate a view with another object. For instance, if you want to associate the button with the third cell in your table view, set the value of the button’s tag property to 3. But there is a problem here: table views have sections, and every section can have n number of cells. We, there‐ fore, have to be able to determine the section as well as the cell that owns our button, and since the tag can represent only one integer, this makes things more difficult. Instead of a tag, therefore, we can ask for the superview of the accessory view, going recursively up the chain of views until we find the cell of type UITableViewCell, like so:
- (UIView *) superviewOfType:(Class)paramSuperviewClass forView:(UIView *)paramView { if (paramView.superview != nil) { if ([paramView.superview isKindOfClass:paramSuperviewClass]) { return paramView.superview; } else { return [self superviewOfType:paramSuperviewClass forView:paramView.superview]; } } return nil; } - (void) performExpand:(UIButton *)paramSender{ /* Handle the tap event of the button */ __unused UITableViewCell *parentCell = (UITableViewCell *)[self superviewOfType:[UITableViewCell class] forView:paramSender]; /* Now do something with the cell if you want to */ NSIndexPath *indexPath = [self.myTableView indexPathForCell:parentCell]; NSLog(@"%@",[NSString stringWithFormat:@"Section %ld, Cell %ld", (long)indexPath.section, (long)indexPath.row]); }
This is a simple recursive method that accepts a view (in this case our button) and a class name (in this case, UITableViewCell), then searches in the view’s super view hi‐ erarchy to find the super view that is of the given class. So it starts with the super view of the given view, and if that super view is not of the required type, looks at the super view’s super view, and so on until it finds the super view of the requested class. You can see that we are using the Class structure as the first parameter to the superviewOf Type:forView: method. This data type can hold any Objective-C class name, and it’s great if you are looking for or asking for specific class names from the programmer.