简体   繁体   English

自定义UITableViewCell按钮动作?

[英]Custom UITableViewCell button action?

I've 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? 我的问题是如何将indexPath传递给action方法?

Right now I'm doing 现在我正在做

 [cell.showRewards addTarget:self action:@selector(myAction:) forControlEvents:UIControlEventTouchUpInside];

In my cellForRowAtIndexPath method and my method is: 在我的cellForRowAtIndexPath方法中,我的方法是:

-(IBAction)myAction:(id)sender{
NSIndexPath *indexPath = [self.tableView indexPathForCell:(MyCustomCell *)[sender superview]];
NSLog(@"Selected row is: %d",indexPath.row);
}

Any tips? 有小费吗? Thanks. 谢谢。

Just want to add what I believe is the best solution of all: a category on UIView. 只想添加我认为最好的解决方案: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: 只需在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
cell.showRewards.tag = indexPath.row;

-(IBAction)myAction:(id)sender
{
UIButton *btn = (UIButton *)sender;
int indexrow = btn.tag;
NSLog(@"Selected row is: %d",indexrow);
}

While I feel setting tag for the button is one way to go. 虽然我觉得为按钮设置tag是一种方法。 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 . 基本上你正在做的是获取相对于tableView的点击发生位置的坐标。 After getting the coordinates, tableView can give you the indexPath by using the method indexPathForRowAtPoint: . 获取坐标后, tableView可以使用方法indexPathForRowAtPoint:为您提供indexPathForRowAtPoint: You are good to go after this... 你很高兴去追寻......

Voila, you have not just the indexPath but also the actual cell where the click happened. 瞧,你不仅有indexPath ,还有点击发生的实际单元格。 To get the actual data from your datasource (assuming its NSArray), you can do - 要从数据源获取实际数据(假设其NSArray),您可以 -

[datasource objectAtIndex:[indexPath row]];

Try this one. 试试这个吧。

cell.showRewards.tag=indextPath.row

implement this in cellforrowatindexpath tableview's method. 在cellforrowatindexpath tableview的方法中实现它。

-(IBAction)myAction:(id)sender{
UIButton* btn=(UIButton*)sender;
NSLog(@"Selected row is: %d",btn.tag);
}

您设置按钮标记值= indexpath并在函数中检查它,如果标记值是这样做你想要的

You can assign indexpath to button tag and access in your method like 您可以将indexpath分配给按钮标记,并在方法中进行访问

cell.showRewards.tag = indexPath.row;

-(IBAction)myAction:(id)sender
{
     NSIndexPath *indexPath = [self.tableView indexPathForCell:[sender tag]];
     NSLog(@"Selected row is: %d",indexPath.row);
}

In custom UITableViewCell class: 在自定义UITableViewCell类中:

[self.contentView addSubview:but_you]; 

In cellForRowAtIndexPath method you can write: cellForRowAtIndexPath方法中,您可以编写:

[cell.showRewards addTarget:self action:@selector(myAction:) forControlEvents:UIControlEventTouchUpInside];    
cell.showRewards.tag = 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 子类化UITableViewCell

The solution I went with was to sub class UITableViewCell 我使用的解决方案是子类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. cellForRowAtIndexPath:创建单元格时cellForRowAtIndexPath:您可能正在使用模型对象来填充单元格数据。 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. 将域对象附加到这样一个专门的UIKit组件感觉就像是不好的做法。

Use Objective-C Associative Objects 使用Objective-C关联对象

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. 在使用模型对象填充单元格时, cellForRowAtIndexPath:下行添加到cellForRowAtIndexPath:方法。 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. 在反思中,虽然我选择了第一个(因为我已经将子类化为子类),但第二个解决方案可能更清晰,因为它仍然是ViewController的附加和检索模型对象的责任。 The UITableViewCell doesn't need to know anything about it. UITableViewCell不需要了解它。

In - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method write the code below: - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法写下面的代码:

  [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. 如果你想要按钮的indexPath 检测在UITableView按下了哪个UIButton描述了如何。

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)
        {
         ...
        }
    }

In [sender superview] you access not MyCustomCell , but it's contentView . [sender superview]您不访问MyCustomCell ,但它是contentView Read UITableViewCell Class Reference: 阅读UITableViewCell类参考:

contentView Returns the content view of the cell object. contentView返回单元格对象的内容视图。 (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. 讨论: UITableViewCell对象的内容视图是单元格显示的内容的默认超级视图。 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] . 修改代码的最简单方法是使用[[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 . contentView出现在iPhoneOS 2.0 Similar future modification will influence your code. 类似的未来修改将影响您的代码。 That the reason why I don't suggest to use this way. 这就是我不建议用这种方式的原因。

这是“最简单的方法”(在IOS11上测试):

NSIndexPath *indexPath = [myTable indexPathForRowAtPoint:[[[sender superview] superview] center]];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM