Using a custom image for a UITableViewCell's accessoryView and having it respond to UITableViewDelegate

anon picture anon · May 15, 2009 · Viewed 87.9k times · Source

I'm using a custom drawn UITableViewCell, including the same for the cell's accessoryView. My setup for the accessoryView happens by the way of something like this:

UIImage *accessoryImage = [UIImage imageNamed:@"accessoryDisclosure.png"];
UIImageView *accImageView = [[UIImageView alloc] initWithImage:accessoryImage];
accImageView.userInteractionEnabled = YES;
[accImageView setFrame:CGRectMake(0, 0, 28.0, 28.0)];
self.accessoryView = accImageView;
[accImageView release];

Also when the cell is initialized, using initWithFrame:reuseIdentifier: I ensured to set the following property:

self.userInteractionEnabled = YES;

Unfortunately in my UITableViewDelegate, my tableView:accessoryButtonTappedForRowWithIndexPath: method (try repeating that 10 times) is not getting triggered. The delegate is definitely wired up properly.

What can be possibly missing?

Thanks all.

Answer

Jim Dovey picture Jim Dovey · May 15, 2009

Sadly that method doesn't get called unless the internal button type provided when you use one of the predefined types is tapped. To use your own, you'll have to create your accessory as a button or other UIControl subclass (I'd recommend a button using -buttonWithType:UIButtonTypeCustom and setting the button's image, rather than using a UIImageView).

Here's some things I use in Outpost, which customizes enough of the standard widgets (just slightly, to match our teal colouring) that I wound up doing my own UITableViewController intermediary subclass to hold utility code for all other table views to use (they now subclass OPTableViewController).

Firstly, this function returns a new detail disclosure button using our custom graphic:

- (UIButton *) makeDetailDisclosureButton
{
    UIButton * button = [UIButton outpostDetailDisclosureButton];

[button addTarget: self
               action: @selector(accessoryButtonTapped:withEvent:)
     forControlEvents: UIControlEventTouchUpInside];

    return ( button );
}

The button will call this routine when it's done, which then feeds the standard UITableViewDelegate routine for accessory buttons:

- (void) accessoryButtonTapped: (UIControl *) button withEvent: (UIEvent *) event
{
    NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint: [[[event touchesForView: button] anyObject] locationInView: self.tableView]];
    if ( indexPath == nil )
        return;

    [self.tableView.delegate tableView: self.tableView accessoryButtonTappedForRowWithIndexPath: indexPath];
}

This function locates the row by getting the location in the table view of a touch from the event provided by the button and asking the table view for the index path of the row at that point.