Ios UITableView中的UITextField未成为第一响应者
我有大约20行的Ios UITableView中的UITextField未成为第一响应者,ios,swift,uitableview,uitextfield,first-responder,Ios,Swift,Uitableview,Uitextfield,First Responder,我有大约20行的UITableView,每行包含一个UITextField。我第一次点击文本字段时会打开键盘,我已经准备好编辑这个文本字段。如果我点击下一个文本字段(注意键盘一直显示),键盘仍然显示,但蓝色光标不在新文本字段中,我无法输入任何文本。但如果我再次点击另一个文本字段,它就可以正常工作。这种行为交替发生,一次有效,另一次无效 无论我是否可以编辑,委托方法textFieldShouldBeginEditing(:)始终被调用。委托方法textfielddebeginediting(:)仅
UITableView
,每行包含一个UITextField
。我第一次点击文本字段时会打开键盘,我已经准备好编辑这个文本字段。如果我点击下一个文本字段(注意键盘一直显示),键盘仍然显示,但蓝色光标不在新文本字段中,我无法输入任何文本。但如果我再次点击另一个文本字段,它就可以正常工作。这种行为交替发生,一次有效,另一次无效
无论我是否可以编辑,委托方法textFieldShouldBeginEditing(:)
始终被调用。委托方法textfielddebeginediting(:)
仅在编辑works时调用
这是cellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TextFieldCell")!
let titleLabel = cell.viewWithTag(1) as! UILabel
let contentTextField = cell.viewWithTag(2) as! FixableTextField
contentTextField.delegate = self
contentTextField.inputAccessoryView = doneToolbar
// Enable/disable editing for text fields
if isEditing {
contentTextField.enableEditing()
} else {
contentTextField.disableEditing()
}
// Present Profile Data
if profileUpdateBuffer != nil {
switch indexPath.row {
case 0:
titleLabel.text = "Count"
contentTextField.text = "\(profileUpdateBuffer!.count)"
contentTextField.purposeID = "count"
contentTextField.keyboardType = .numberPad
case 1:
titleLabel.text = "City"
contentTextField.text = "\(profileUpdateBuffer!.city)"
contentTextField.purposeID = "city"
contentTextField.keyboardType = .default
// ...
case 20:
titleLabel.text = "Name"
contentTextField.text = "\(profileUpdateBuffer!.name)"
contentTextField.purposeID = "name"
contentTextField.keyboardType = .default
default:
titleLabel.text = ""
contentTextField.text = ""
}
return cell
}
// No data available -> show info in first row
else {
if indexPath.row == 0 {
titleLabel.text = "No data"
contentTextField.text = "No data"
}
else {
titleLabel.text = ""
contentTextField.text = ""
}
return cell
}
}
enablediting()
和disableEditing()
方法来自类FixableTextField
。我可以看到文本字段始终处于启用状态,因为我可以看到文本字段边框
// Extract from FixableTextField class
func enableEditing() {
self.isEnabled = true
self.borderStyle = .roundedRect
}
func disableEditing() {
self.isEnabled = false
self.borderStyle = .none
}
UITextField的代码
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
// Delete empty field indicator "-"
if textField.text == "-" {
textField.text = ""
}
//Move profileTable's contentView to correct position
if textField is FixableTextField {
let path = IndexPath(row: rowMap[(textField as! FixableTextField).purposeID]!, section: 0)
moveContentViewUp(indexPath: path)
}
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
// Save new value to profileUpdateBuffer
do {
try self.profileUpdateBuffer?.setProperty(value: textField.text!, key: (textField as! FixableTextField).purposeID)
} catch ProfileError.PropertySettingWrongType {
let falseInputAlert = UIAlertController(title: "False Input", message: "The input for this field is not valid.", preferredStyle: .alert)
falseInputAlert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(falseInputAlert, animated: true, completion: nil)
} catch {
print("Error when trying to set property for profileUpdateBuffer in ProfileViewController")
}
// Display new data in table
profileTable.reloadData()
}
从classProfileData
中的setProperty
方法中提取profileUpdateBuffer
属于ProfileData
func setProperty(value:String, key:String) throws {
switch key {
case "count":
count = value
case "city":
count = value
// ...
case "name":
name = value
default:
throw ProfileError.PropertySettingWrongType
}
}
我制作了一个小程序来模仿你描述的行为。
问题似乎是由textfielddidediting(:)
末尾的表视图数据重新加载引起的:
尝试删除profileTable.reloadData()
,以确认问题的根本原因(是的,您的其他单元格将不会更新)
解决此问题的一种方法是在textfielddidediting(:)
中的visibleCells
上使用直接单元格更新。我看到profileUpdateBuffer?
是您的数据模型。只要从模型中手动更新单元格的标题标签和文本字段属性(如果它们位于表视图的visible cells属性中)
如果要相应地调整单元格大小,请使用AutoLayout和UITableViewAutomaticDimension
作为表视图行高,并结合使用BeginUpdate()
/EndUpdate()
调用
关于如何在不失去键盘焦点的情况下实现直接单元格操作和/或动态单元格大小更新的更多详细信息,我已经回答了
希望这会有帮助 我认为问题在于调用profileTable.reloadData()。。。您可能应该只重新加载一个单元格。可能会使用旧TextField作为参数调用TextFieldDiEndediting(:),然后为新TextField调用textFieldShouldBeginEditing(:)。问题是您刷新了TextFielddEndediting(:)末尾的所有单元格,这意味着系统作为参数传递给textFieldShouldBeginEditing(:)的TextField可能不一定与相应单元格包含的相同。。。这些新的按键可能会被发送到属于可重用单元格队列中某个单元格的文本字段,即不可见,但仍存在于内存中的某个位置。请发布您的代码,以便我们可以帮助您。尤其是您的cellForRowAt Indexath函数。如何将侦听器添加到文本字段?谢谢,我当然会。在“textFieldShouldBeginEditing(:)”中有任何过滤逻辑吗?我看到你也有你的VC设置为代表你所有的文本字段。您是否有逻辑来区分委托方法实现中的单元?您可以尝试在单元格中移动TextField delegate,这样每个单元格将自行负责。您是否总是在TextField shouldbeginediting
中返回true
。如果没有,可以发布代码吗?想象一下这样的场景:单元格1和单元格2分别有文本字段1(tf1)和文本字段2(tf2)。您正在编辑tf1。然后选择tf2。该框架将退出tf1上的第一响应者,并成为tf2上的第一响应者。这将触发tf2的shouldBeginEditing。现在,作为对tf1上已辞职的响应者的响应,tf1的委托将被调用为didEndEditing。但您正在编辑tf2,而不是tf1!此调用将有效地使tf2不可编辑。你能在代码中添加一些日志并确认这是真的吗?如果为真,请尝试通过在单元格中移动tf代表来解决此问题。非常感谢您的详细回答。你是对的,当我删除profileTable.reloadData()
。正如你所说,我通过在没有realodData的情况下更新单元格来修复它,现在一切都正常了。您是否解释了在使用reloadData
时发生此行为的原因?当您启动reloadData()
时,表视图正在禁用自身上的用户交互。然后,对于becomeFirstResponder()
,单元格将返回false。在您的情况下,第二个单元不会成为第一响应者。如果然后选择一个新单元格,则不会调用reloadData()
,因为前一个单元格没有成为第一响应者,因此不会调用didEndEditing()(reloadding位于何处)。这就是为什么可以编辑第三个单元格。我不知道为什么当编辑不可用时,键盘仍然在屏幕上-我原以为当前一个文本字段辞去第一响应者时,它会被取消。完美的解释。谢谢!
func textFieldDidEndEditing(_ textField: UITextField) {
// Save new value to profileUpdateBuffer
do {
try self.profileUpdateBuffer?.setProperty(value: textField.text!, key: (textField as! FixableTextField).purposeID)
} catch ProfileError.PropertySettingWrongType {
let falseInputAlert = UIAlertController(title: "False Input", message: "The input for this field is not valid.", preferredStyle: .alert)
falseInputAlert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(falseInputAlert, animated: true, completion: nil)
} catch {
print("Error when trying to set property for profileUpdateBuffer in ProfileViewController")
}
// Display new data in table
profileTable.reloadData()
}