Two buttons in a UITableViewCell: How to tell which indexPath was selected?

前端 未结 2 1033
甜味超标
甜味超标 2021-01-13 10:08

I want to place two buttons in each table view cell. When I click on button number one I want the app to show an alert message: \"You tapped button1 at indexpath:3,0\". My

相关标签:
2条回答
  • 2021-01-13 10:32

    Using indexPath as the tag value is OK when you have only one button in a UITableCell but if you want to track more you can use modulo operator:

        - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:              
        (NSIndexPath *)indexPath {
        ...
        imageButton1.tag=indexPath.row*2; 
        [imageButton1 addTarget:self action:@selector(buttonPushed:)
        [cell.contentView addSubview:imageButton];
    
    
        ...
        imageButton2.tag=indexPath.row*2+1; 
        [imageButton2 addTarget:self action:@selector(buttonPushed:)
        [cell.contentView addSubview:imageButton];
    

    for the selector you can distinguish between the buttons and get the indexPath like this:

    -(void) buttonPushed:(id)sender{
     UIButton *button = (UIButton *)sender;
    
        switch (button.tag%2) {
            case 0:  // imageButton1 is pressed
    
    // to reach indexPath of the cell where the button exists you can use:
    //         ((button.tag-button.tag%2)/2)
    
            break;
    
            case 1: // imageButton2 is pressed
    
            break;
        }
    

    The example is for 2 buttons but you can adjust it according to the number of buttons.

    0 讨论(0)
  • 2021-01-13 10:50

    Taking @wedo's answer and simplifying it a bit -- you essentially need two pieces of information : the row and column number that was tapped ("column" being the order of the button).


    Solution 1 - Not a Bad Solution

    This can be stored on a button using button.tag and button.titleLabel.tag. In -tableView:cellForRowAtIndexPath: you would do this:

    UIButton *button0 = [UIButton buttonWithType:UIButtonTypeCustom];
    button0.tag = indexPath.row;
    button0.titleLabel.tag = 0; // button #0 (or column 0)
    [button0 addTarget:self action:@selector(cellButtonAction:)
                            forControlEvents:UIControlEventTouchUpInside];
    [cell.contentView addSubview:button0]; 
    

    Your cellButtonAction: method would look like this:

    - (IBAction)answerButtonAction:(UIButton *)sender {
       NSInteger row = sender.tag;
       NSInteger column = sender.titleLabel.tag;
       // do something
    }
    

    Solution 2 - A Much Better Solution

    The above works and it's fine, but it is rather hacky. Alternately, it is maybe 3 minutes work to subclass a button and add a property that can hold row and column values.

    @interface IndexPathButton: UIButton
    
    // NSIndexPath provides a convenient way to store an integer pair
    // Note we are using cellIndex.section to store the column (or button #)
    @property (strong, nonatomic) NSIndexPath *cellIndex;
    
    @end
    
    @implementation IndexPathButton
    @end
    

    You would use this in much the same way as the previous solution, but store the values in the custom property rather than tags. In tableView:cellForRowAtIndexPath:

    // You'd create a button for each column here
    IndexPathButton *button0 = [IndexPathButton buttonWithType:UIButtonTypeCustom];
    button0.indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:0];
    [button0 addTarget:self action:@selector(cellButtonAction:)
                            forControlEvents:UIControlEventTouchUpInside];
    [cell.contentView addSubview:button0]; 
    

    Solution 3 - The Best Solution

    UITableViewCells should generally use delegation for any heavy lifting that needs to be done. This pattern most closely matches Apples own delegate pattern for cells, e.g. tableView:didSelectRowAtIndexPath and friends. So, let's create a tableViewCell base class that can be used to handle any number of controls and which doesn't need to pass around indexPaths.

    /** Simple protocol to allow a cell to fire any type of action from a control. */
    @protocol SOTableViewCellActionDelegate <NSObject>
    
    @required
    -(void)tableViewCell:(UITableViewCell *)cell didFireActionForSender:(id)sender;
    
    @end 
    
    @interface SOActionCell : UITableViewCell
    
    @property (nonatomic, weak) id<SOTableViewCellActionDelegate> delegate;
    
    @end
    
    @implementation SOActionCell
    
    -(void)fireAction:(id)sender
    {
       [self.delegate tableViewCell:self didFireActionForSender:sender]; 
    }
    
    @end
    

    In -tableView:cellForRowAtIndexPath: you would do this:

    UIButton *button0 = [UIButton buttonWithType:UIButtonTypeCustom];
    button0.tag = 0;
    [button0 addTarget:cell action:@selector(fireAction:)
                            forControlEvents:UIControlEventTouchUpInside];
    [cell.contentView addSubview:button0]; 
    

    Then implement the required delegate method in the tableViewController:

    -(void)tableViewCell:(UITableViewCell *)cell didFireActionForSender:(id)sender
    {
       NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
       NSAssert(indexPath, @"indexPath of cell shall always be found."];
       if (!indexPath)
          return;
    
       // do whatever you want to do with your button action here
       // using indexPath, sender tag, button title, etc.
    }
    
    0 讨论(0)
提交回复
热议问题