UITableView reloadData自动调用resignFirstResponder

时间:2011-06-20 09:41:29

标签: ios uitableview resignfirstresponder

我有这个带有自定义单元格的UITableView,它只能获得预定义的值,因此我使用UIPickerView作为它们的inputView。在我编辑一个字段并需要显示其更新值之前,一切都很快乐。

为了使事情更清晰,更容易维护,我将委托和数据源作为单独的类,并使用通知使它们与tableView交互。因此,在从UIPickerView中选择一个值之后,tableView的数据源会得到通知,然后通知主ViewController,它包含对tableView的引用。从那里我打电话

[_tableView reloadData];

并且一切似乎都有效,除了UIPickerView消失之外,我认为因为细胞被重新生成并且在某处调用了一些resignFirstResponder,或类似的东西。 有没有其他方法可以使tableView更新其值而无需在某个地方实现自定义方法,这会非常难看?

13 个答案:

答案 0 :(得分:25)

这就像预期的行为一样 - 选择器属于特定的单元格,该单元格被重新加载并且不再是第一个响应者。我无论如何必须选择一个特定元素才能让选择器出现,即使其成为第一响应者。

因此,您需要在重新加载后再次成为第一响应者,或直接更新特定单元格。

答案 1 :(得分:22)

中加入:

[yourSearchBar becomeFirstResponder];

之后:

[_tableView reloadData];

做了这个伎俩

答案 2 :(得分:12)

我遇到了同样的问题,上面的答案都没有完美(我看到键盘上下弹跳等)。
this SO post之后,我通过调用

解决了问题
[tableView beginUpdates];
[tableView endUpdates]; 

这对我有用,表行获得更新,甚至扩展/缩小(如果你动态地改变行高)动画很好,所有这些都没有让第一响应者退出,甚至没有开始键盘解除。
这不会滚动您的表格视图以适应任何展开的行,因此我将上面的代码段放在专用方法中,例如:

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

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

答案 3 :(得分:7)

我通过继承UITextView,重写 - (BOOL)resignFirstResponder并添加BOOL canResign解决了这个问题。此变量在重新加载数据之前设置,并在之后的短时间内取消设置。

答案 4 :(得分:6)

你可以采用这种方法,而不是最好的方法,但它有效:

// 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 :(得分:3)

我将UISearchBar放在UITableView的自己的部分中。在启动搜索时,我确保只刷新不包含搜索栏的部分。

img

答案 6 :(得分:1)

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

自定义文本字段派生自UITextField。

.h

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

<强>的.m

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

确保在重新加载表格视图时,您的自定义文字字段未重新创建

答案 7 :(得分:0)

如果您在搜索栏中遇到此问题,以下是在iOS 6中为我做的:

  • 实例化UISearchBar并将其作为子视图添加到顶部的UITableView。
  • 在UITableView中创建一个虚拟的第一个单元格,以便搜索栏仅阻止此虚拟单元格,而不是阻止包含数据的实际单元格。

答案 8 :(得分:0)

正如@Eiko所说,这对我有用!

使用UIPickerViewDelegate&#39; 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];
}

答案 9 :(得分:0)

快速解决方案:

我们可以通过继承UITextfiled来覆盖默认的canResignFirstResponder

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

你需要在reload语句之前和之后设置canResign变量。

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

不要忘记将自定义类文本字段指定为CustomField。

答案 10 :(得分:0)

跟踪哪个单元格的键盘处于活动状态,然后通过cellForRowAtIndexPath获取该特定单元格,并使其成为textView firstResponder

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

答案 11 :(得分:0)

我使用 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()

答案 12 :(得分:-1)

您可以通过暂时将第一响应者状态转移到其他对象来解决此问题。通常,您将输入视图的控件传输到ViewController。由于您的UIViewController也继承自UIResponder,您可以执行以下操作:

on didSelect { ....

[yourViewController成为FirstRespoder];

[_ tableView reloadData];

[yourInputField becomeFirstResponder];

.... }

因此,一旦重新加载表格,您就可以将firstResponder状态转回标签/字段。 默认情况下,canBecomeFirstResponder设置为NO。因此,您可能需要在ViewController中覆盖相同的内容。此外,您可能需要使视图控制器的inputView与UIPicker相同,否则它可能会解除您的选择器并显示键盘。