Custom UITableViewCell button action?
I'开发者_如何学Cve been looking around to find a solution to this, but can't seem to find one that works for me. I have a custom cell with a button inside. My problem is how do I pass the indexPath to the action method?
Right now I'm doing
[cell.showRewards addTarget:self action:@selector(myAction:) forControlEvents:UIControlEventTouchUpInside];
In my cellForRowAtIndexPath method and my method is:
-(IBAction)myAction:(id)sender{
NSIndexPath *indexPath = [self.tableView indexPathForCell:(MyCustomCell *)[sender superview]];
NSLog(@"Selected row is: %d",indexPath.row);
}
Any tips? Thanks.
cell.showRewards.tag = indexPath.row;
-(IBAction)myAction:(id)sender
{
UIButton *btn = (UIButton *)sender;
int indexrow = btn.tag;
NSLog(@"Selected row is: %d",indexrow);
}
Just want to add what I believe is the best solution of all: a category on UIView.
It's as simple as this:
- (void)somethingHappened:(id)sender
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:[sender parentCell]];
// Your code here...
}
Just use this category on UIView:
@interface UIView (ParentCell)
- (UITableViewCell *)parentCell;
@end
@implementation UIView (ParentCell)
- (UITableViewCell *)parentCell
{
UIView *superview = self.superview;
while( superview != nil ) {
if( [superview isKindOfClass:[UITableViewCell class]] )
return (UITableViewCell *)superview;
superview = superview.superview;
}
return nil;
}
@end
While I feel setting tag
for the button is one way to go. You might need to write code to make sure each time the cell gets reused, the appropriate tag gets updated on the button object.
Instead I have a feeling this could work. Try this -
-(IBAction)myAction:(id)sender
{
CGPoint location = [sender locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
UITableViewCell *swipeCell = [self.tableView cellForRowAtIndexPath:indexPath];
NSLog(@"Selected row: %d", indexPath.row);
//......
}
Essentially what you are doing is getting the coordinates of where the click happened with respect to your tableView
. After getting the coordinates, tableView
can give you the indexPath by using the method indexPathForRowAtPoint:
. You are good to go after this...
Voila, you have not just the indexPath
but also the actual cell where the click happened. To get the actual data from your datasource (assuming its NSArray), you can do -
[datasource objectAtIndex:[indexPath row]];
Try this one.
cell.showRewards.tag=indextPath.row
implement this in cellforrowatindexpath tableview's method.
-(IBAction)myAction:(id)sender{
UIButton* btn=(UIButton*)sender;
NSLog(@"Selected row is: %d",btn.tag);
}
You set the button tag value = indexpath and check it in function if tag value is this do what u want
In custom UITableViewCell
class:
[self.contentView addSubview:but_you];
In cellForRowAtIndexPath
method you can write:
[cell.showRewards addTarget:self action:@selector(myAction:) forControlEvents:UIControlEventTouchUpInside];
cell.showRewards.tag = indexPath.row;
You can assign indexpath to button tag and access in your method like
cell.showRewards.tag = indexPath.row;
-(IBAction)myAction:(id)sender
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:[sender tag]];
NSLog(@"Selected row is: %d",indexPath.row);
}
I find it incredible that there isn't really a decent solution to this.
For whatever reason, I find the tagging methods and the 'using the visual location of the cell on the screen to identify the correct model object' outlined in the other answers a bit dirty.
Here are two different approaches to the problem:
Subclassing UITableViewCell
The solution I went with was to sub class UITableViewCell
@interface MyCustomCell : UITableViewCell
@property (nonatomic, strong) Model *myModelObject;
@end
When creating the cell in cellForRowAtIndexPath:
you are likely to be using the model object to populate the cell data. In this method you can assign the model object to the cell.
And then in the button tap handler:
MatchTile *cell = (MatchTile *) sender.superview.superview;
if (cell && cell.myModelObject)
{
//Use cell.myModelObject
}
I'm not 100% happy with this solution to be honest. Attaching domain object to such a specialised UIKit component feels like bad practice.
Use Objective-C Associative Objects
If you don't want to subclass the cell there is a another bit of trickery you can use to associate the model object with the cell and retrieve it later.
To retrieve the model object from the cell, you will need a unique key to identify it. Define one like this:
static char* OBJECT_KEY = "uniqueRetrievalKey";
Add the following line to your cellForRowAtIndexPath:
method when you are using the model object to populate the cell. This will associate your model object with the cell object.
objc_setAssociatedObject(cell, OBJECT_KEY, myModelObject, OBJC_ASSOCIATION_RETAIN);
And then anywhere you have a reference to that cell you can retrieve the model object using:
MyModelObject *myModelObject = (MyModelObject *) objc_getAssociatedObject(cell, OBJECT_KEY);
In reflection, although I opted for the first (because I'd already subclassed the cell), the second solution is probably a bit cleaner since it remains the responsibility of the ViewController to attach and retrieve the model object. The UITableViewCell doesn't need to know anything about it.
In [sender superview]
you access not MyCustomCell
, but it's contentView
.
Read UITableViewCell
Class Reference:
contentView
Returns the content view of the cell object. (read-only)
@property(nonatomic, readonly, retain) UIView *contentView
Discussion:
The content view of a UITableViewCell
object is the default superview for content displayed by the cell. If you want to customize cells by simply adding additional views, you should add them to the content view so they will be positioned appropriately as the cell transitions into and out of editing mode.
Easiest way to modify your code is to use [[sender superview] superview]
.
But this will stop working if you later modify your cell and insert button in another view.
contentView appeared in iPhoneOS 2.0
. Similar future modification will influence your code. That the reason why I don't suggest to use this way.
In - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method write the code below:
[cell.zoomButton addTarget:self action:@selector(navigateAction:) forControlEvents:UIControlEventTouchUpInside];
cell.zoomButton.tag=indexPath.row;
Then write a method like this:
-(IBAction)navigateAction:(id)sender
{
UIButton *btn = (UIButton *)sender;
int indexrow = btn.tag;
NSLog(@"Selected row is: %d",indexrow);
currentBook = [[bookListParser bookListArray] objectAtIndex:indexrow];
KitapDetayViewController *kitapDetayViewController;
if(IS_IPHONE_5)
{
kitapDetayViewController = [[KitapDetayViewController alloc] initWithNibName:@"KitapDetayViewController" bundle:Nil];
}
else
{
kitapDetayViewController = [[KitapDetayViewController alloc] initWithNibName:@"KitapDetayViewController_iPhone4" bundle:Nil];
}
kitapDetayViewController.detailImageUrl = currentBook.detailImageUrl;
kitapDetayViewController.bookAuthor = currentBook.bookAuthor;
kitapDetayViewController.bookName = currentBook.bookName;
kitapDetayViewController.bookDescription = currentBook.bookDescription;
kitapDetayViewController.bookNarrator=currentBook.bookNarrator;
kitapDetayViewController.bookOrderHistory=currentBook.bookOrderDate;
int byte=[currentBook.bookSizeAtByte intValue];
int mb=byte/(1024*1024);
NSString *mbString = [NSString stringWithFormat:@"%d", mb];
kitapDetayViewController.bookSize=mbString;
kitapDetayViewController.bookOrderPrice=currentBook.priceAsText;
kitapDetayViewController.bookDuration=currentBook.bookDuration;
kitapDetayViewController.chapterNameListArray=self.chapterNameListArray;
// [[bookListParser bookListArray ]release];
[self.navigationController pushViewController:kitapDetayViewController animated:YES];
}
If you want the indexPath of the button Detecting which UIButton was pressed in a UITableView describe how to.
basically the button action becomes:
- (void)checkButtonTapped:(id)sender
{
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
if (indexPath != nil)
{
...
}
}
Here is the "Simplest Way" to do it (Tested on IOS11):
NSIndexPath *indexPath = [myTable indexPathForRowAtPoint:[[[sender superview] superview] center]];
精彩评论