I’ve got a UITableViewController subclass that is subclassed by two other classes. In some of the cells of both tables I have an image that the user can click on to perform an action. It all works and I’m happy except that in one of the 2 subclasses the first row of that table has an issue. You can only click the image by clicking to the rightmost edge of the image. If you click in the body of the image it calls the table’s didSelectRowAtIndexPath instead.
What boggles me is that it works in the other class for all rows and even in the one it doesn’t work for it works in all the other rows where that image shows up. Here’s the code I’m using to add the image and gesture recognizer into my cell:
UIImageView *imgparent = [[UIImageView alloc] initWithFrame:CGRectMake(offsetleftmain, 24.0, 14.0, 16.0)];
imgparent.image = [UIImage imageNamed:@"item_open.png"];
imgparent.tag = ITEMOPENTAG;
// add listener
imgparent.userInteractionEnabled = YES;
UITapGestureRecognizer *singleFingerDTapParent = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(loadChildren:)];
[imgparent addGestureRecognizer:singleFingerDTapParent];
[singleFingerDTapParent release];
[cell.contentView addSubview:imgparent];
[imgparent release];
I’m testing in the simulator by the way. I’ve tried replacing the image with a button but still the problem persists. Any ideas?
EDIT: Here’s the beginnings of the code that is called when the image is clicked. Again, this works but in the case of that one row it only works if you click on the right edge of the image. I’ve attached a screenshot to illustrate. The first circle indicates where I have to tap in order to get my gesture to be called. The second shows an example in the very same table that allows you to click the entire image. I’m confounded.
- (void)loadChildren:(UIGestureRecognizer *)gestureRecognizer {
NSLog(@"loadChildren");
// get the cell
UITableViewCell *cell = (UITableViewCell *)gestureRecognizer.view.superview.superview;
UIImageView *imgvw = (UIImageView *)[cell viewWithTag:ITEMOPENTAG]; // open arrow
[imgvw setHidden:YES]; // hide open arrow
imgvw = (UIImageView *)[cell viewWithTag:ITEMCLOSETAG]; // close arrow
[imgvw setHidden:NO]; // show close arrow
// get the record for the cell
NSIndexPath *indexPath = [tableView indexPathForCell:cell];
}

EDIT: Here’s the complete tableView:cellForRowAtIndexPath:indexPath. Keep in mind that it’s being called from the cellForRowAtIndexPath of 2 other subclasses of this class, each simply passing in an identifier withType:
- (UITableViewCell *)tableView:(UITableView *)tv
cellForRowAtIndexPath:(NSIndexPath *)indexPath
withType:(NSString *)s_type
{
UITableViewCell *cell = nil;
// if dealing with empty region then show no tasks cell
if(s_type == @"noTasksCell"){
cell = [tv dequeueReusableCellWithIdentifier:@"noTasksCell"];
if( cell == nil ) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:@"noTasksCell"] autorelease];
}
cell.textLabel.text = @"No tasks";
cell.textLabel.textColor = [UIColor lightGrayColor];
cell.textLabel.font = [UIFont systemFontOfSize:14];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
UILabel *lblMain;
NSDictionary *o_rec = [self getRecForPath:indexPath];
NSString *s_cell = @"rowCell";
BOOL b_parent = NO;
BOOL b_parentOpen = NO;
BOOL b_child = NO;
BOOL b_checked = NO;
if([self isParent:indexPath]){
b_parent = YES;
b_parentOpen = !([o_rec objectForKey:@"b_open"] == nil || [[o_rec objectForKey:@"b_open"] isEqualToNumber:[NSNumber numberWithInt:0]]);
s_cell = [s_cell stringByAppendingString:@"Parent"];
}
if([o_rec objectForKey:@"b_child"] != nil){
b_child = YES;
s_cell = [s_cell stringByAppendingString:[NSString stringWithFormat:@"Child%@",[o_rec objectForKey:@"indent"]]];
}
if([[o_rec objectForKey:@"checked"] isEqualToNumber:[NSNumber numberWithInt:1]]){
b_checked = YES;
s_cell = [s_cell stringByAppendingString:@"isComplete"];
}
// add the following to the name:
// - project id
// - width of table to the name so that rotations will change the cell dequeue names
// - priority
s_cell = [s_cell stringByAppendingFormat:
@"Proj%@Width%dP%@"
,[o_rec objectForKey:@"project_id"]
,(int)tv.bounds.size.width
,[[o_rec objectForKey:@"priority"] stringValue]
];
cell = [tv dequeueReusableCellWithIdentifier:s_cell];
if( cell == nil ) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:s_cell] autorelease];
cell.textLabel.hidden = YES; // hide the regular text label
cell.selectedBackgroundView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
cell.selectedBackgroundView.backgroundColor = [delegate colorForHexWithAlpha:0xffcc66ff];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
int offsetleftmain = 10;
if(b_child){
offsetleftmain += ([[o_rec objectForKey:@"indent"] intValue]-1) * 18;
}
if(b_parent){
// parent arrow
UIImageView *imgparent = [[UIImageView alloc] initWithFrame:CGRectMake(offsetleftmain, 24.0, 14.0, 16.0)];
imgparent.image = [UIImage imageNamed:@"item_open.png"];
imgparent.tag = ITEMOPENTAG;
// add listener
imgparent.userInteractionEnabled = YES;
UITapGestureRecognizer *singleFingerDTapParent = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(loadChildren:)];
singleFingerDTapParent.numberOfTapsRequired = 1;
singleFingerDTapParent.numberOfTouchesRequired = 1;
[imgparent addGestureRecognizer:singleFingerDTapParent];
[singleFingerDTapParent release];
[cell.contentView addSubview:imgparent];
[imgparent release];
// close arrow
UIImageView *imgparent2 = [[UIImageView alloc] initWithFrame:CGRectMake(offsetleftmain-2, 24.0, 16.0, 14.0)];
imgparent2.image = [UIImage imageNamed:@"item_close.png"];
imgparent2.tag = ITEMCLOSETAG;
imgparent2.userInteractionEnabled = YES;
UITapGestureRecognizer *singleFingerDTapParent2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideChildren:)];
[imgparent2 addGestureRecognizer:singleFingerDTapParent2];
[singleFingerDTapParent2 release];
[cell.contentView addSubview:imgparent2];
[imgparent2 release];
}
offsetleftmain += 18;
// checkbox
UIImageView *imgchk = [[UIImageView alloc] initWithFrame:CGRectMake(offsetleftmain, 20.0, 24.0, 24.0)];
imgchk.image = [UIImage imageNamed:@"check_empty.png"];
imgchk.tag = EMPTYCHECKTAG;
// add listener
imgchk.userInteractionEnabled = YES;
UITapGestureRecognizer *singleFingerDTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(checkOnItem:)];
[imgchk addGestureRecognizer:singleFingerDTap];
[singleFingerDTap release];
[cell.contentView addSubview:imgchk];
[imgchk release];
// checked checkbox
UIImageView *imgchk2 = [[UIImageView alloc] initWithFrame:CGRectMake(offsetleftmain, 20.0, 24.0, 24.0)];
imgchk2.image = [UIImage imageNamed:@"check_checked.png"];
imgchk2.tag = CHECKTAG;
// add listener
imgchk2.userInteractionEnabled = YES;
UITapGestureRecognizer *singleFingerDTap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(checkOffItem:)];
[imgchk2 addGestureRecognizer:singleFingerDTap2];
[singleFingerDTap2 release];
[cell.contentView addSubview:imgchk2];
[imgchk2 release];
offsetleftmain += 28;
// main label
lblMain = [[UILabel alloc] initWithFrame:CGRectMake(offsetleftmain, 22.0, tv.bounds.size.width-offsetleftmain-10, 30.0)];
lblMain.tag = MAINLABELTAG;
lblMain.numberOfLines = 4;
lblMain.font = delegate.font_dflt;
// change color based on priority
if (5-[[o_rec objectForKey:@"priority"] intValue] == 1)
lblMain.textColor = [UIColor redColor];
else if (5-[[o_rec objectForKey:@"priority"] intValue] == 2)
lblMain.textColor = [delegate colorForHexWithAlpha:H_P2COLOR];
else if (5-[[o_rec objectForKey:@"priority"] intValue] == 3)
lblMain.textColor = [delegate colorForHexWithAlpha:H_P3COLOR];
[cell.contentView addSubview:lblMain];
[lblMain release];
// show action sheet for long press and hold
UILongPressGestureRecognizer *clicknHold = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(cellClicknHold:)];
[cell addGestureRecognizer:clicknHold];
[clicknHold release];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// task text
lblMain = (UILabel *)[cell viewWithTag:MAINLABELTAG];
lblMain.text = [self formatContent:[o_rec objectForKey:@"content"]];
CGRect newFrame = lblMain.frame;
newFrame.size.height = [[o_rec objectForKey:@"height"] floatValue];
//newFrame.size.height = [[o_rec objectForKey:@"height"] floatValue]+12;
lblMain.frame = newFrame;
// set checked status
[(UIImageView *)[cell viewWithTag:EMPTYCHECKTAG]
setHidden:[[o_rec objectForKey:@"checked"] boolValue]];
[(UIImageView *)[cell viewWithTag:CHECKTAG]
setHidden:![[o_rec objectForKey:@"checked"] boolValue]];
// show open arrow if dealing with parent cell
if (b_parent) {
//NSLog(@"b_parentOpen:%d",b_parentOpen);
[(UIImageView *)[cell viewWithTag:ITEMOPENTAG] setHidden:b_parentOpen];
[(UIImageView *)[cell viewWithTag:ITEMCLOSETAG] setHidden:!b_parentOpen];
}
return cell;
}
Just in case someone runs into a similar issue as rare as that may be maybe this will help avoid someone going bald pulling their hair out. So my problem wasn’t with the tableView itself but a sidebar I have that is similar to the facebook sidebar that slides in and out. My sidebar has a tableview in it and that table has a header on it that for some reason when it was right beside my other table was somehow preventing clicks to the image in that first row. My solution was simply to position that sidebar view a little bit further offscreen away from the view it was beside instead of being right next to it. Problem solved. Thanks to all who tried to help me out.