[ACCEPTED]-UITableView reloadData automatically calls resignFirstResponder-resignfirstresponder

Accepted answer
Score: 25

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

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

Score: 22

adding:

[yourSearchBar becomeFirstResponder];

after your:

[_tableView reloadData];

did the trick

0

Score: 22

I met the same problem, none of the answers 10 above worked perfectly (I see the keyboard 9 bouncing up and down, etc.).
Following this SO post I 8 fixed the issue by calling

[tableView beginUpdates];
[tableView endUpdates]; 

this worked for 7 me, table rows get updates and even expand/shrink 6 (if you are changing rows height dynamically) with 5 a nice animation, all without resigning 4 first responder or even starting keyboard 3 dismiss.
This will not scroll your table 2 view to fit any expanded row, so I put the 1 snippet above in dedicated method, f.e.:

- (void)tableView:(UITableView *)tableView reloadRowWhileShowingKeyboard:(NSIndexPath *)indexPath 
{  
    [tableView beginUpdates];
    [tableView endUpdates]; 

    [tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
Score: 8

You can follow this approach, not the best, but 1 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];
});
Score: 8

I solved this by subclassing UITextView, overriding 4 -(BOOL)resignFirstResponder and by adding 3 a BOOL canResign. this variable is set before 2 reloading the data and unset a short time 1 after.

Score: 3
customTextField.canResign = NO;
[self.tableView reloadData];
customTextField.canResign = YES;

Custom text field is derived from UITextField.

.h

@interface CustomTextField : UITextField
@property (nonatomic,assign) BOOL canResign;
@end

.m

- (BOOL)canResignFirstResponder
{
    return self.canResign;
}

Make 2 sure that your custom text field is not recreated on 1 table view reloading.

Score: 3

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

- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
Score: 3

Swift solution:

we can override default canResignFirstResponder 4 by subclassing UITextfiled

class CustomField: UITextField{
    var canResign:Bool = false
    override var canResignFirstResponder: Bool{
        return canResign
    }  
}

all you need to 3 set canResign variable before and after 2 reload statement.

cell.offerInputTextField.canResign = false
tableView.reloadData()
cell.offerInputTextField.canResign = true

don't forget to assign 1 the custom class text field as CustomField.

Score: 1

Here my solution. Think that search textfield 2 is in index 0.. You need to update or add 1 or remove next rows..

let beforeCount = self.filteredItems.count
self.filteredItem = ... next filtered items

var removalIndexPaths = [IndexPath]()
var appendalIndexPaths = [IndexPath](
var modifyIndexPaths = [IndexPath]()
self.tableView.beginUpdates()
let deleteAvailable = beforeCount != 0
if deleteAvailable {
    for i in stride(from: beforeCount - 1, to: 0, by: -1) {
        removalIndexPaths.append(IndexPath(row: i, section: 0))
     }
}
        
let appendAvailable = self.filteredShots.count != 0
if appendAvailable {
     for i in stride(from: 1, to: self.filteredShots.count, by: 1) {
         appendalIndexPaths.append(IndexPath(row: i, section: 0))
      }
 }
        
 modifyIndexPaths = appendalIndexPaths.filter { appendPath in
      if appendPath == removalIndexPaths.filter({ $0 == appendPath }).first {
         return true
     } else {
         return false
     }
 }
        
for item in modifyIndexPaths {
     if let rai = appendalIndexPaths.firstIndex(where: { $0 == item}) {
          appendalIndexPaths.remove(at: rai)
     }
     if let rri = removalIndexPaths.firstIndex(where: { $0 == item}) {
           removalIndexPaths.remove(at: rri)
      }
}
        
if modifyIndexPaths.count > 0 {
      self.tableView.reloadRows(at: modifyIndexPaths, with: .none)
}
        
if removalIndexPaths.count > 0 {
      self.tableView.deleteRows(at: removalIndexPaths, with: .none)
}
        
if appendalIndexPaths.count > 0 {
       self.tableView.insertRows(at: appendalIndexPaths, with: .none)
}
               
self.tableView.endUpdates()
Score: 0

If you are facing this issue with a search 2 bar, the following did it for me in iOS 1 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.
Score: 0

As mentioned by @Eiko, this works for me!

Update 1 the cell in UIPickerViewDelegate's pickerView:didSelectRow:inComponent: method:

- (void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
  TableViewCell *cell = (TableViewCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:pickerView.tag inSection:0]];

  /*
  Update your cell here. 
  */

  // Reload TableViewCell will resign the PickerView, so we need to focus it back.  
  [self.tableView reloadData];
  NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
  NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
  [self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationNone];
  [cell.textField becomeFirstResponder];
}
Score: 0

Track which cell's keyboard is active and 2 then get that particular cell by cellForRowAtIndexPath and make 1 textView firstResponder

self.tableView.reloadData()
if let indexPath = self.activeIndexPath{
   if let cell = createFormTableView.cellForRow(at: indexPath) as? TextViewTableViewCell {
        cell.txtViewInput.becomeFirstResponder()
   }
}
Score: 0

I use beginUpdate and endUpdate After end update, get the cell 2 contains the textfield already has focus 1 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()

More Related questions