Ios UITableView中的UITextField未成为第一响应者

Ios UITableView中的UITextField未成为第一响应者,ios,swift,uitableview,uitextfield,first-responder,Ios,Swift,Uitableview,Uitextfield,First Responder,我有大约20行的UITableView,每行包含一个UITextField。我第一次点击文本字段时会打开键盘,我已经准备好编辑这个文本字段。如果我点击下一个文本字段(注意键盘一直显示),键盘仍然显示,但蓝色光标不在新文本字段中,我无法输入任何文本。但如果我再次点击另一个文本字段,它就可以正常工作。这种行为交替发生,一次有效,另一次无效 无论我是否可以编辑,委托方法textFieldShouldBeginEditing(:)始终被调用。委托方法textfielddebeginediting(:)仅

我有大约20行的
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()
}
从class
ProfileData
中的
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()
}