UITableView新增cell后内部UITextField调用becomeFirstResponder失败如何解决
问题根源
你当前代码的核心问题有三个:
- 你手动调用了数据源方法
self.tableView(self.tableView, cellForRowAt: indexPath),这个方法每次调用都会生成一个全新的单元格实例,这个实例根本没有被添加到当前屏幕的视图层级中,调用它的focus方法自然不会生效 - 固定0.25秒的延时逻辑不可靠,受设备性能、列表长度、动画时长影响,很容易出现执行focus逻辑时单元格还没有完成渲染的情况
becomeFirstResponder()返回false的本质是对应的UITextField此时不在当前的响应链上,无法接收交互事件
解决方案
首先将全局reloadData替换为更轻量的行插入方法,再通过CATransaction捕获滚动动画的完成时机,在动画结束、单元格已经渲染完成后,调用UITableView实例自带的cellForRow(at:)方法获取真实渲染在屏幕上的单元格实例,再执行聚焦逻辑。
修改后的核心代码如下:
@IBAction func createItem(_ sender: UIBarButtonItem) { let newIndex = model.count let indexPath = IndexPath(item: newIndex, section: 0) model.append("new item") // 批量更新插入行,替代全局reloadData tableView.performBatchUpdates { tableView.insertRows(at: [indexPath], with: .automatic) } completion: { [weak self] _ in guard let self = self else { return } // 捕获滚动动画完成事件 CATransaction.begin() CATransaction.setCompletionBlock { // 获取真实渲染在屏幕上的单元格 guard let targetCell = self.tableView.cellForRow(at: indexPath) as? ItemUI else { return } targetCell.focus() } self.tableView.scrollToRow(at: indexPath, at: .top, animated: true) CATransaction.commit() } }
额外注意事项
- 请确认xib/Storyboard中UITextField的
isUserInteractionEnabled属性为开启状态(默认是true,若手动关闭会导致聚焦失败) - 请确认UITextField已经被添加到单元格的contentView视图层级中
- 不要手动调用你自己实现的数据源
tableView(_:cellForRowAt:)方法获取单元格,该方法是供UITableView内部调用生成单元格用的,手动调用拿到的实例不在当前视图树上
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

