How to find indexPath for tapped button in tableView Using Seque

后端 未结 3 556
别那么骄傲
别那么骄傲 2020-12-05 09:16

I have a UITableView using prototype cell.

The cells have a UIButton that show a UIViewController (Modal) using Segue

相关标签:
3条回答
  • 2020-12-05 09:26

    Very simple solution, if you want to point to the same segue of the selected cell.

    - (IBAction)buttonPressed:(id)sender {
    
        CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
        NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
    
        [self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
    
    }
    
    0 讨论(0)
  • 2020-12-05 09:31

    Forget for a moment that you are using storyboard, and let's try to follow the best approach.

    You have several solution, but for my opinion, just 1 of these is optimal: delegation pattern.

    First, you should extend your cell, and using delegation to return the cell when the user press the button. Then, you should use indexPathForCell to get the indexPath.

    Let's see the approaches:

    Cell by button position

    - (void)buttonClicked:(id)sender
      CGPoint buttonPosition = [sender convertPoint:CGPointZero
                                       toView:self.tableView];
      NSIndexPath *tappedIP = [self.tableView indexPathForRowAtPoint:buttonPosition];
    
      // When necessary 
      // UITableViewCell *clickedCell = [self.tableView cellForRowAtIndexPath:tappedIP];
    }
    

    the solution above is certainly the most rapid to implement, but it is not the best from the point of view of the design/architecture. Moreover you get the indexPath but you need then to calculate every other info. This is a cool method, but would say not the best.

    Cell by while cycle on the button superviews

    // ContactListViewController.m
    
    - (IBAction)emailContact:(id)sender {
        YMContact *contact = [self contactFromContactButton:sender];
        // present composer with `contact`...
    }
    
    - (YMContact *)contactFromContactButton:(UIView *)contactButton {
        UIView *aSuperview = [contactButton superview];
        while (![aSuperview isKindOfClass:[UITableViewCell class]]) {
            aSuperview = [aSuperview superview];
        }
        YMContactCell *cell = (id) aSuperview;
        NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
        return [[self fetchedResultsController] objectAtIndexPath:indexPath];
    }
    

    Get the cell in this way is less performant of the former, and it is not elegant as well.

    Cell by button tag

    - (CustomCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
        CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
        cell.theLabel.text = self.theData[indexPath.row];
        cell.button.tag = indexPath.row;
        [cell.button addTarget:self action:@selector(doSomething:) forControlEvents:UIControlEventTouchUpInside];
        return cell;
    }
    
    -(void)doSomething:(UIButton *) sender {
        NSLog(@"%@",self.theData[sender.tag]);
        //sender.tag will be equal to indexPath.row
    }
    

    Absolutely no. Use the tag could seem a cool solution, but the tag of a control can be used for other reasons, like the next responder etc. I don't like this approach.

    Cell by design pattern

    // YMContactCell.h
    @protocol YMContactCellDelegate
    - (void)contactCellEmailWasTapped:(YMContactCell*)cell;
    @end
    
    @interface YMContactCell
    @property (weak, nonatomic) id<YMContactCellDelegate> delegate;
    @end
    
    // YMContactCell.m
    - (IBAction)emailContact:(id)sender {
        [self.delegate contactCellEmailWasTapped:self];
    }
    
    // ContactListViewController.m
    - (void)contactCellEmailWasTapped:(YMContactCell*)cell;
        NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
        YMContact *contact = [[self fetchedResultsController] objectAtIndexPath:indexPath];
        // present composer with `contact` ...
    }
    

    This is my favourite solution. Using delegation or blocks is a really nice approach and you can pass all the parameters you want. In fact you could want to send back directly the needed info, without having to calculate them later.

    Enjoy ;)

    0 讨论(0)
  • 2020-12-05 09:43

    First make a global int variable selecteIndex;

    In your cell, give your button tag similar to cell's indexPath.row value

    E.g. btn.tag = indexPath.row;

    The assing & call action on click of that button

    [btn addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
    
    -(void)buttonClicked:(id)sender
    {
        UIButton *btn = (UIButton*)sender;
        selectedIndex = btn.tag;
        [self performSegueWithIdentifier:@"segueName" sender:self];
    }
    

    Then at end of your view write this function

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
        if ([segue.identifier isEqualToString:@"segueName"]) {
            viewController *dvc = (viewController *)[segue destinationViewController];
            [dvc setSelected:selectedIndex];
        };
    }
    
    0 讨论(0)
提交回复
热议问题