Подтвердить что ты не робот

UITableView reloadData автоматически вызывает resignFirstResponder

У меня есть этот UITableView с пользовательскими ячейками, которые могут получать только предопределенные значения, поэтому я использую UIPickerView как свой входной вид. Все отлично, пока я не отредактирую поле и не покажу его обновленное значение.

Чтобы сделать вещи более ясными и удобными в обслуживании, я сделал делегаты и источники данных отдельными классами и использовал уведомления, чтобы они взаимодействовали с tableView. Таким образом, после того, как значение выбрано из UIPickerView, источник данных tableView получает уведомление и, в свою очередь, уведомляет главный ViewController, который содержит ссылку на tableView. Оттуда я звоню

[_tableView reloadData];

и все работает, за исключением того, что UIPickerView исчезает, я думаю, потому что ячейки регенерированы и где-то вызывается какой-то resignFirstResponder или что-то в этом роде. Есть ли другой способ заставить tableView обновлять свои значения без необходимости реализовывать собственный способ где-то, что делает это, что было бы довольно уродливо?

4b9b3361

Ответ 1

Это читается как ожидаемое поведение - сборщик принадлежит к определенной ячейке, эта ячейка перезагружается и уже не является первым ответчиком. Я предполагаю, что в любом случае нужно было выбрать конкретный элемент для выбора сборщика, т.е. Сделать его первым ответчиком.

Таким образом, вам нужно либо снова стать первым ответчиком после перезагрузки, либо напрямую обновить конкретную ячейку.

Ответ 2

добавление:

[yourSearchBar becomeFirstResponder];

после вашего:

[_tableView reloadData];

сделал трюк

Ответ 3

Я встретил ту же проблему, ни один из вышеперечисленных ответов не работал отлично (я вижу, что клавиатура подпрыгивает вверх и вниз и т.д.).
После this SO post я исправил проблему, вызвав

[tableView beginUpdates];
[tableView endUpdates]; 

это сработало для меня, строки таблицы получают обновления и даже расширяют/сокращают (если вы динамически изменяете высоту строк) с приятной анимацией, все без отставки первого ответчика или даже пуска клавиатуры. Это не будет прокручивать представление таблицы, чтобы соответствовать любой расширенной строке, поэтому я помещаю фрагмент выше в выделенный метод, f.e.:

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

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

Ответ 4

Вы можете следовать этому подходу, а не лучше, но он работает:

// 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

Я решил это путем подкласса UITextView, переопределения - (BOOL) resignFirstResponder и добавления BOOL canResign. эта переменная устанавливается перед перезагрузкой данных и отменяется через короткое время после.

Ответ 6

Я поместил свой UISearchBar в свой раздел в UITableView. При отстреливании поиска я только обновил разделы, которые не содержат строку поиска.

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

Ответ 7

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

Пользовательское текстовое поле выводится из UITextField.

.h

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

ого

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

Убедитесь, что ваше текстовое поле не воссоздано при перезагрузке таблицы.

Ответ 8

Если вы столкнулись с этой проблемой со строкой поиска, в iOS 6 это было сделано для меня:

  • Создайте экземпляр UISearchBar и добавьте его как subview в свой UITableView вверху.
  • Создайте фиктивную первую ячейку в вашем UITableView, чтобы панель поиска только блокировала эту фиктивную ячейку, а не вашу фактическую ячейку с данными.

Ответ 9

Как упоминалось @Eiko, это работает для меня!

Обновить ячейку в методе UIPickerViewDelegate pickerView:didSelectRow:inComponent::

- (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];
}

Ответ 10

Быстрое решение:

мы можем переопределить default canResignFirstResponder путем подкласса UITextfiled

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

все, что вам нужно, чтобы установить переменную canResign до и после перезагрузки.

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

не забудьте назначить настраиваемое текстовое поле класса как CustomField.

Ответ 11

Отслеживать, какая клеточная клавиатура активна, а затем получить эту конкретную ячейку cellForRowAtIndexPath и сделать textView firstResponder

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

Ответ 12

Я использую beginUpdate и endUpdate. После завершения обновления, чтобы ячейка содержала текстовое поле, у вас уже есть фокус, тогда сделайте его первым ответчиком

    self.tableView.beginUpdates()
    self.tableView.reloadRows(at: [indexPath], with: .automatic)
    self.tableView.endUpdates()
    let newCell = self.tableView.cellForRow(at: indexPath)
    newCell.textField.becomeFirstResponder()

Ответ 13

Вы можете решить эту проблему, временно передав статус первого ответчика другому объекту. Обычно вы передаете управление видом ввода в ViewController. Поскольку ваш UIViewController также наследуется от UIResponder, вы можете сделать что-то вроде этого:

on didSelect { ....

[yourViewController статьFirstRespoder];

[_ tableView reloadData];

[yourInputField статьFirstResponder];

.... }

Таким образом, как только таблица будет перезагружена, вы можете перенести статус firstResponder обратно в свой ярлык/поле. По умолчанию для canBecomeFirstResponder установлено значение NO. Поэтому вам может потребоваться переопределить это в вашем ViewController. Кроме того, вам может потребоваться сделать inputView для вашего контроллера представлений таким же, как ваш UIPicker, иначе он может просто отклонить ваш сборщик и отобразить клавиатуру.