48

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

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

[_tableView reloadData];

一切似乎都正常,除了 UIPickerView 消失了,我认为是因为单元格被重新生成并且在某处调用了一些 resignFirstResponder 或类似的东西。有没有其他方法可以让 tableView 更新其值,而不必在某处实现自定义方法,这会很丑陋?

4

14 回答 14

24

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

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

于 2011-06-20T12:06:46.777 回答
22

添加:

[yourSearchBar becomeFirstResponder];

在你之后:

[_tableView reloadData];

成功了

于 2011-10-28T13:53:47.740 回答
22

我遇到了同样的问题,上面的答案都不是完美的(我看到键盘上下弹跳等)。
这篇 SO 帖子之后,我通过调用解决了这个问题

[tableView beginUpdates];
[tableView endUpdates]; 

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

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

    [tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
于 2015-08-13T08:43:44.973 回答
8

您可以遵循这种方法,不是最好的,但它有效:

// 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];
});
于 2013-05-09T13:02:35.897 回答
8

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

于 2013-09-23T22:32:27.117 回答
3
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;
}

确保在重新加载表格视图时不会重新创建您的自定义文本字段。

于 2014-09-18T00:12:53.167 回答
3

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

- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
于 2015-09-17T11:35:38.880 回答
3

快速解决方案:

我们可以通过继承 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。

于 2018-04-09T06:08:18.020 回答
1

这是我的解决方案。认为搜索文本字段位于索引 0 中。您需要更新或添加或删除下一行。

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()
于 2021-09-30T09:36:06.150 回答
0

如果您在使用搜索栏时遇到此问题,请在 iOS 6 中为我完成以下操作:

  • 实例化一个 UISearchBar 并将其作为子视图添加到顶部的 UITableView 中。
  • 在你的 UITableView 中创建一个虚拟的第一个单元格,以便搜索栏只阻止这个虚拟单元格,而不是你的实际单元格的数据。
于 2012-11-17T16:13:09.117 回答
0

正如@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];
}
于 2015-01-06T02:46:53.027 回答
0

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

self.tableView.reloadData()
if let indexPath = self.activeIndexPath{
   if let cell = createFormTableView.cellForRow(at: indexPath) as? TextViewTableViewCell {
        cell.txtViewInput.becomeFirstResponder()
   }
}
于 2018-07-19T10:11:00.957 回答
0

我使用beginUpdateendUpdate 结束更新后,获取包含文本字段的单元格已经具有焦点,然后使其成为第一响应者

    self.tableView.beginUpdates()
    self.tableView.reloadRows(at: [indexPath], with: .automatic)
    self.tableView.endUpdates()
    let newCell = self.tableView.cellForRow(at: indexPath)
    newCell.textField.becomeFirstResponder()
于 2018-10-09T19:37:36.100 回答
-1

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

在 didSelect { ....

[yourViewController 成为FirstRespoder];

[_tableView 重载数据];

[您的输入字段成为FirstResponder];

....}

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

于 2013-04-15T10:20:11.287 回答