UITableView reloadData automatically calls resignF

2019-01-11 00:42发布

I have this UITableView with custom cells that can get only predefined values, therefore I use a UIPickerView as their inputView. All is jolly good until I edit a field and need to show its updated value.

In order to make things clearer and easier to maintain, I made delegates and data sources as separate classes, and use notifications to make them interact with the tableView. So, after a value has been chosen from the UIPickerView, the tableView's data source gets notified, and in turn notifies the main ViewController that holds a reference to the tableView. From there I call

[_tableView reloadData];

and everything seems to work, except that the UIPickerView disappears, I think because the cells are regenerated and somewhere some resignFirstResponder is called, or something like that. Is there any other way to make the tableView updating its values without having to implement a custom method somewhere that does it, which would be quite ugly?

13条回答
爷、活的狠高调
2楼-- · 2019-01-11 00:56

I put my UISearchBar in its own section in a UITableView. When firing off the search, I made sure to only refresh the sections which do not contain the search bar.

- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
查看更多
Bombasti
3楼-- · 2019-01-11 00:57

You can solve this issue by temporarily transferring the first responder status to other object. Usually you transfer the control of input view to your ViewController. Since your UIViewController also inherits from UIResponder, you can do something like this:

on didSelect { ....

[yourViewController becomeFirstRespoder];

[_tableView reloadData];

[yourInputField becomeFirstResponder];

.... }

Thus, once the table is reloaded, you can transfer firstResponder status back to your label/field. By default, the canBecomeFirstResponder is set to NO. So you might need to override the same in your ViewController. Also, you might need to make the inputView for your view controller the same as your UIPicker, otherwise it might just dismiss your picker and display a keyboard.

查看更多
Animai°情兽
4楼-- · 2019-01-11 00:59

You can follow this approach, not the best, but it works:

// pass the responder to a temporary (hidden) textField
[_tmpTextField becomeFirstResponder];

// reload data
[_tableView reloadData];

// reloadData is definitely async... 
// so pass the responder back in a timed op
double delayInSeconds = 0.1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [_textField becomeFirstResponder];
});
查看更多
时光不老,我们不散
5楼-- · 2019-01-11 01:04

I use beginUpdate and endUpdate After end update, get the cell contains the textfield already has focus then make it first responder

    self.tableView.beginUpdates()
    self.tableView.reloadRows(at: [indexPath], with: .automatic)
    self.tableView.endUpdates()
    let newCell = self.tableView.cellForRow(at: indexPath)
    newCell.textField.becomeFirstResponder()
查看更多
唯我独甜
6楼-- · 2019-01-11 01:06

This reads like expected behavior - the picker belongs to a particular cell, that cell gets reloaded and is not the first responder any more. I guess one had to select a specific element anyway for the picker to appear, i.e. to make it first responder.

So you either need to make it become first responder again after reloading, or update the specific cell directly.

查看更多
够拽才男人
7楼-- · 2019-01-11 01:06

If you are facing this issue with a search bar, the following did it for me in iOS 6:

  • Instantiate a UISearchBar and add it as a subview to your UITableView at the top.
  • Create a dummy first cell in your UITableView so that the search bar only blocks this dummy cell and not your actual cell with data.
查看更多
登录 后发表回答