I have a UITableViewController (called Details). In that tableView on row 1 I have another UITableView which I rotate horizontally. Each cell in that tableview is a custom UITableViewCell (called DetailsHorizontalPhotoCell) which displays a button with an image. I am having a hard time taking action when the photos (the buttons) are pressed.
Calling an IBAction is not a problem for me if I have that IBAction code in the DetailsHorizontalPhotoCell.h/.m files however I need to present a modal VC upon the button presses. That code does not belong and/or work in a tableViewCell - it needs to be in the controller (Details). That being said I can't figure out how to code it. This is what I have so far.
Details.m:
if( (indexPath.row == 1) && ([detailsObject_.photo count] > 0) )
{
NSLog(@"** In Photo Section **");
static NSString *CellIdentifier = @"cellPhoto";
DetailsHorizontalPhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[DetailsHorizontalPhotoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
CGAffineTransform rotateTable = CGAffineTransformMakeRotation(-M_PI_2);
cell.horizontalTableView.transform = rotateTable;
NSArray *photoArray = [[NSArray alloc] initWithArray:detailsObject_.photo];
cell.horizontalTableView.frame = CGRectMake(0, 0, cell.horizontalTableView.frame.size.width, cell.horizontalTableView.frame.size.height);
cell.contentArray = [NSArray arrayWithArray:photoArray];
cell.horizontalTableView.allowsSelection = YES;
return cell;
}
DetailsHorizontalPhotoCell.m:
@synthesize horizontalTableView = horizontalTableView_;
@synthesize contentArray = contentArray_;
@synthesize imageButton = imageButton_;
// *** a bunch of code which is not relevant to this question snipped out here...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [self.horizontalTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
for(UIButton *button in cell.subviews)
{
[button removeFromSuperview];
}
// create image and button
UIImage *image = [UIImage imageNamed:[contentArray_ objectAtIndex:indexPath.row]];
self.imageButton = [[UIButton alloc] initWithFrame:CGRectMake(5, 5, 240, 240)];
// setup the button
[imageButton_ setImage:image forState:UIControlStateNormal];
imageButton_.layer.masksToBounds = YES;
imageButton_.layer.cornerRadius = 5.0;
imageButton_.layer.borderWidth = 1.0;
imageButton_.layer.borderColor = [[UIColor grayColor] CGColor];
// rotate the button
CGAffineTransform rotateButton = CGAffineTransformMakeRotation(M_PI_2);
imageButton_.transform = rotateButton;
// this detects the click of each photo and triggers the IBAction
[imageButton_ addTarget:self action:@selector(photoButton:) forControlEvents:UIControlEventTouchUpInside];
/// do more stuff yada yada yada... <snipped code> and return cell;
}
// the Action (which I know should NOT be in this UITableViewCell class)
- (IBAction)photoButton:(id)sender
{
CGPoint hitPoint = [sender convertPoint:CGPointZero toView:self.horizontalTableView];
NSIndexPath *hitIndex = [self.horizontalTableView indexPathForRowAtPoint:hitPoint];
NSLog(@"Image clicked, index: %d", hitIndex.row);
// presentModalViewController here - but you can't do that from here! Must be in the Details controller
}
So, knowing that I can't perform a presentModalViewController from the Cell I try to move that code into the Details class (below)
Add the IBAction to Details.h and .m
- (IBAction)photoButton:(id)sender
{
DetailsHorizontalPhotoCell *cell = [[DetailsHorizontalPhotoCell alloc] init];
CGPoint hitPoint = [sender convertPoint:CGPointZero toView:cell.horizontalTableView];
NSIndexPath *hitIndex = [cell.horizontalTableView indexPathForRowAtPoint:hitPoint];
NSLog(@"Image clicked, index: %d", hitIndex.row);
}
And add the click event to the photo button in the Details cellForRowAtIndexPath method.
// Blaaahh! Tried a million combinations of something like below but cannot get it to work...
//[cell.imageButton addTarget:cell.horizontalTableView action:@selector(photoButton:) forControlEvents:UIControlEventTouchUpInside];
PS - I'm using IOS5, Xcode 4.2 w/ ARC
First of all there is no need to add the button each time a cell is displayed. You only have to add the subviews of the cell when you create a new cell. You'll get better scrolling performance this way.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [self.horizontalTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
// Add image button to cell
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(5, 5, 240, 240)];
// set tag so you can get the button later
button.tag = 1021;
[button addTarget:self action:@selector(photoButton:) forControlEvents:UIControlEventTouchUpInside]
// more button config
[cell.contentView addSubView:button];
}
// get image button
UIButton *button = [cell.contentView viewWithTag:1021];
// configure image button
UIImage *image = [UIImage imageNamed:[contentArray_ objectAtIndex:indexPath.row]];
[button setImage:image forState:UIControlStateNormal];
return cell;
}
Next you can use use superview on the button (= sender) to go back to the UITableViewCell. With the cell you can get the indexPath of that cell.
- (IBAction)photoButton:(id)sender
{
UIView *contentView = [sender superview];
UITableViewCell *cell = [contentView superview];
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
}