indexPathForRowAtPoint returns nil only for first cell in a uitableview

风格不统一 提交于 2019-11-27 06:50:43

问题


I have a UIButton inside of a custom UITableViewCell that removes the cell when the button is pressed. In order to get the indexPath of the cell the button is in, I'm calling indexPathForRowAtPoint: in a method called when the button is pressed as follows:

-(void)buttonPressed:(UIButton *)sender{
    CGPoint btnPosition = [sender convertPoint:CGPointZero toView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:btnPosition];

    if (indexPath != nil)
    {
    //remove the cell from the tableview. 
    }
}

This works fine if I press the button in any cell except the first cell, and also when if there is ONLY one cell in the table. However, if there are multiple cells and I press the button in the first cell, the button press is triggered and the btnPosition is found, but [self.tableView indexPathForRowAtPoint:btnPosition]; returns nil.

For example, if there are three cells, each with a button:

  1. I press the first cell button: buttonPressed is called but indexPath is nil, so nothing happens.
  2. I press the third cell button: buttonPressed is called and the cell is removed as expected.
  3. I press the first cell again: same as before, buttonPressed called but indexPath is nil.
  4. I press the second cell button: buttonPressed is called and the cell is removed as expected.
  5. I press the first cell button: This time, buttonPressed is called, indexPath is not nil and the cell is removed as expected.

I've checked that the tableView is not nil, as suggested by a related, but different, post. I've also confirmed that the point btnPosition is set to the same value (x=260, y=44.009995) both when [self.tableView indexPathForRowAtPoint:btnPosition] == nil AND when [self.tableView indexPathForRowAtPoint:btnPosition] != nil.

So aside from asking if anyone has any ideas on what could be happening here, my question is:

Under what circumstances could passing the same CGPoint to [self.tableView indexPathForRowAtPoint:btnPosition] return a different (or nil) indexPath?

I'd appreciate help with any ideas of where I might look to track this down, or to hear if anyone has encountered a similar issue.

Some additional notes that might be helpful (please excuse if I make a question asking faux-pas. I'll happily take your feedback about that as well :)

  • This tableView is part of a UITableViewController which is embedded in a UINavigationController

  • The tableView has 3 sections, 2 of which are hidden from view (0 rows, no footer, no header) while I'm presenting the section with the button cell rows as described.

  • I'm adjusting the location of the buttons during presentation by programmatically changing their horizontal constraints.

  • The heights of my customUITableViewCell, tableViewRows and UIButton are each equal to 60.0f


回答1:


Just try this:

fix target selector:

[button addTarget:self action:@selector(buttonPressed:event:)forControlEvents:UIControlEventTouchUpInside];


- (void)buttonPressed:(id)sender event:(id)event{
    UITouch *touch = [[event allTouches] anyObject];
    CGPoint touchPos = [touch locationInView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:touchPos];
    if(indexPath != nil){
        //do operation with indexPath
    }
}



回答2:


I feel awful that I will get points for this, but @rmaddy's comment worked wonders for my code. I want to put this as an answer since I missed his comment the first time round and spent ages implementing a longer fix. Thanks rmaddy for the fix:

As an experiment, try using CGPointMake(5,5) instead of CGPointZero. Does that make any difference?

rmaddy then explained why it worked:

Given that you were using CGRectZero and the fact that the y coordinate of btnPosition was a strange value (44.009995 instead of 44), I suspected you may have either had an edge case or been victim to roundoff error. By choosing a point that wasn't in the absolute corner of the view, you had a better chance of avoiding roundoff issues.

rmaddy - this issue has been bugging me for 2 weeks... and you fixed it. Thank you very much. Can I donate any points on stackoverflow to you?




回答3:


I am going to share the way I do this type of functionality. This will work if you have one section. You don't need these 2 lines:

CGPoint btnPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:btnPosition];

In your cellForRowAtIndexPath while adding a custom cell add these line:

cell.btn.tag = indexPath.row;
[button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];

And in buttonPressed do this:

-(void)buttonPressed:(UIButton *)sender{
    UIButton *btn = (UIButton *)sender;
    //Remove the btn.tag number row.
}

For more than 1 section you can do this:

-(void)buttonPressed:(UIButton *)sender{
    UIButton *btn = (UIButton *)sender;
    UITableViewCell *cell = (UITableViewCell *)btn.superview;
    UITableView *tableView = (UITableView *)cell.superview;
    NSIndexPath *indexPath = [tableView indexPathForCell:cell];
    //Remove this cell in indePath
}

Hope this helps .. :)




回答4:


Add UITapGestureRecognizer to UIButton as well as add a target Method for GestureObject.

UITapGestureRecognizer *tapGestureDelete=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(callAMethod:)];
    [yourDeleteButton addGestureRecognizer:tapGestureDelete];

In taget callAMethod retrieve the gestured position as below

-(void)callAMethod:(UIGestureRecognizer *)gestureRecognizer
{
NSIndexPath *currentIndexPath = [self.tableView indexPathForRowAtPoint:[gestureRecognizer locationInView:self.talbleView]];
    if(currentIndexPath != nil) 
   { 
       // remove the cell from tableview 
   }
}

I Hope It will work...




回答5:


simalone's answer in Swift (as of version 2.2) will be:

tableViewCell.button.addTarget(self, action: #selector(buttonPressed(_:event:)), forControlEvents: .TouchUpInside)
...
@IBAction func buttonPressed(sender: UIButton, event: UIEvent) {
    if let touchPos = event.allTouches()?.first?.locationInView(self.TableView),
       let indexPath = self.TableView.indexPathForRowAtPoint(touchPos)?.row {
            // do operations with indexPath
    }
}


来源:https://stackoverflow.com/questions/22368525/indexpathforrowatpoint-returns-nil-only-for-first-cell-in-a-uitableview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!