Implementing Prev./Next buttons in UITableView to make first responder a UITextField in a non-visible cell

StackOverflow https://stackoverflow.com/questions/15911513

Question

in my app I have a UITabeView with UITextFields inside every cell. However I'm having troubles implementing previous/next buttons to make the text field inside the previous/next UITableViewCell be the first responder.

I've subclassed the UITableViewCell class to have it call a certain method of it's delegate when the prev./next buttons are pressed and to pass the cell itself as a parameter of this method (so I can get its index path to calculate which is the index path of the cell whose text field has to be made first responder)

In the implementation of the delegate's method I:

  • get the index path of the cell whose button was pressed
  • add or subtract 1 from the index path of that cell (depending on which button was pressed)
  • get the cell whose textfield has to be made first responder using the -cellForRowAtIndexPath: method on the table view
  • make the text field first responder

Problem is that the -cellForRowAtIndexPath: method returns the cell only if it is visible. So when the cell is not visible it will return nil and the above algorithm will not work while when the cell is on screen it will work correctly.

Here is my code for the prev. button, provided that MUInfoMateriaTableViewCell is my subclass of UITableViewCell and that it has a textField property that returns its text field:

- (void)prevButtonPressedInCell:(MUInfoMateriaTableViewCell *)cell
{
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    NSIndexPath *previousIndexPath = [NSIndexPath indexPathForRow:indexPath.row-1 inSection:indexPath.section];

    MUInfoMateriaTableViewCell *newCell = (MUInfoMateriaTableViewCell *)[self.tableView cellForRowAtIndexPath:previousIndexPath];
    [newCell.textField becomeFirstResponder];
}

Is there any way to "get" a cell that is not visible so I can make its text field the first responder? Or can you suggest me another algorithm to work around this problem?

Was it helpful?

Solution

You can fix this with a multi-step process:

  • keep track of the cell that contains the desired text field to make first responder
  • calculate the NSIndexPath of the cell to be shown and call [self.tableView scrollToRowAtIndexPath:atScrollPosition:animated:] to bring it into view
  • implement tableView:willDisplayCell:forRowAtIndexPath: to call becomeFirstResponder on the desired cell when it becomes visible and it matches the desired cell or index path

The last step is important because calling becomeFirstResponder doesn't do anything if the receiver isn't a subview of any window.

OTHER TIPS

Make the cell visibile by scrolling the table view, using scrollToRowAtIndexPath:atScrollPosition:animated:.

For instance

- (void)prevButtonPressedInCell:(MUInfoMateriaTableViewCell *)cell
{
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    NSIndexPath *previousIndexPath = [NSIndexPath indexPathForRow:indexPath.row-1 inSection:indexPath.section];

    [self.tableView scrollToRowAtIndexPath:previousIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];

    MUInfoMateriaTableViewCell *newCell = (MUInfoMateriaTableViewCell *)[self.tableView cellForRowAtIndexPath:previousIndexPath];
    [newCell.textField becomeFirstResponder];
}

Problem is that the -cellForRowAtIndexPath: method returns the cell only if it is visible.

That's because the cell doesn't exist when its row isn't visible. UITableView only keeps those cells it needs to draw the table. That's why you get lots of -tableView:cellForRowAtIndexPath: messages when you scroll the table -- the table is asking its data source to provide the cells that it doesn't have.

If you want to use your current approach, you'll need to scroll the table so that the row about to be edited becomes visible, as demonstrated in Gabriele Petronella's answer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top