如何将 InputAccessoryView 中的 TextField 设置为第一响应者 [Swift]

问题描述

好的,所以我有一个带有 textField 的 tableView,当用户点击 tableView 中的 textField 时,键盘显示一个自定义 InputAccessoryView。它看起来像这样:

enter image description here

这是创建自定义 InputAccessoryView 的代码,我在 cellForRowAt 和 textFieldDidBeginEditing(如下)为 tableView(每行执行不同的功能)中尝试过。

func textFieldDidBeginEditing(_ textField: UITextField) {
        print("textFieldDidBeginEditing")
        if textField.tag == 1 {
            profileDataTextField.addToolbarInputAccessoryView()
        }
}

我已经将它创建为 UITextField 的扩展:

extension UITextField {

func addToolbarInputAccessoryView() {
    let screenWidth = UIScreen.main.bounds.width
    // Create Main Container View
    let mainContainerView = UIView()
    mainContainerView.backgroundColor = .clear
    mainContainerView.frame = CGRect(x: 0,y: 0,width: screenWidth,height: 120)
    
    // Create heading Label
    let label = UILabel()
    label.textColor = .white
    label.font = UIFont(name: "BrandonGrotesque-Bold",size: 20)
    label.text = "Enter New Weight"
    label.widthAnchor.constraint(equalToConstant: screenWidth).isActive = true
    label.heightAnchor.constraint(equalToConstant: 30.0).isActive = true
    label.textAlignment = .center
    
    // Create Input Container View
    let inputContainerView = UIView()
    inputContainerView.backgroundColor = .white
    inputContainerView.heightAnchor.constraint(equalToConstant: 80.0).isActive = true
    inputContainerView.widthAnchor.constraint(equalToConstant: screenWidth).isActive = true
    
    // Create inputTextField
    let inputTextField = UITextField()
    inputTextField.translatesAutoresizingMaskIntoConstraints = false
    inputTextField.placeholder = "150"
    inputTextField.textAlignment = .left
    inputTextField.textColor = .darkGray
    inputTextField.font = UIFont(name: "BrandonGrotesque-Bold",size: 50)
    inputTextField.backgroundColor = .white
    inputTextField.layer.cornerRadius = 4
    inputTextField.layer.masksToBounds = true
    inputTextField.borderStyle = .none
    
    // Create metricTextField
    let metricLabel = UILabel()
    metricLabel.textColor = .darkGray
    metricLabel.font = UIFont(name: "BrandonGrotesque-Bold",size: 18)
    metricLabel.text = "lbs"
    metricLabel.textAlignment = .left
    
    // Create Done button
    let doneButton = UIButton()
    doneButton.backgroundColor = .systemIndigo
    doneButton.setTitle("Done",for: .normal)
    doneButton.titleLabel?.font = UIFont(name: "BrandonGrotesque-Bold",size: 20)
    doneButton.cornerRadius = 4
    doneButton.translatesAutoresizingMaskIntoConstraints = false
    doneButton.addTarget(self,action: #selector(doneTapped),for: .touchUpInside)
    
    // Create cancel button
    let cancelButton = UIButton()
    cancelButton.backgroundColor = .systemRed
    cancelButton.setTitle("Cancel",for: .normal)
    cancelButton.titleLabel?.font = UIFont(name: "BrandonGrotesque-Bold",size: 20)
    cancelButton.cornerRadius = 4
    cancelButton.translatesAutoresizingMaskIntoConstraints = false
    cancelButton.addTarget(self,action: #selector(cancelTapped),for: .touchUpInside)
    
    // Main Stack View
    let mainStackView = UIStackView()
    mainStackView.axis = .vertical
    mainStackView.distribution = .fill
    mainStackView.alignment = .fill
    mainStackView.spacing = 10.0
    mainStackView.backgroundColor = .clear
    
    // Toolbar StackView
    let toolbarStackView = UIStackView()
    toolbarStackView.axis = .horizontal
    toolbarStackView.distribution = .fillEqually
    toolbarStackView.alignment = .fill
    toolbarStackView.spacing = 20.0
    toolbarStackView.backgroundColor = .white
    
    // Input Stackview
    let inputStackView = UIStackView()
    inputStackView.axis = .horizontal
    inputStackView.distribution = .equalCentering
    inputStackView.alignment = .center
    inputStackView.spacing = 5.0
    inputStackView.backgroundColor = .white
    
    // Put it all together
    mainStackView.addArrangedSubview(label)
    
    inputStackView.addArrangedSubview(inputTextField)
    inputStackView.addArrangedSubview(metricLabel)
    
    toolbarStackView.addArrangedSubview(cancelButton)
    toolbarStackView.addArrangedSubview(inputStackView)
    toolbarStackView.addArrangedSubview(doneButton)
    toolbarStackView.translatesAutoresizingMaskIntoConstraints = false
    
    inputContainerView.addSubview(toolbarStackView)
    
    mainStackView.addArrangedSubview(inputContainerView)
    mainStackView.translatesAutoresizingMaskIntoConstraints = false
    
    toolbarStackView.leadingAnchor.constraint(equalTo: inputContainerView.leadingAnchor,constant: 15).isActive = true
    toolbarStackView.trailingAnchor.constraint(equalTo: inputContainerView.trailingAnchor,constant: -15).isActive = true
    toolbarStackView.topAnchor.constraint(equalTo: inputContainerView.topAnchor,constant: 15).isActive = true
    toolbarStackView.bottomAnchor.constraint(equalTo: inputContainerView.bottomAnchor,constant: -15).isActive = true
    
    mainContainerView.addSubview(mainStackView)
    
    inputAccessoryView = mainContainerView
}

@objc func cancelTapped() {
    self.resignFirstResponder()
}

@objc func doneTapped() {
    self.resignFirstResponder()
}

}

问题是,当键盘似乎将其设置为第一响应者而不是原始 textField 时,我不知道如何在 InputAccessoryView 中引用 textField(图像中的“150”)。

我希望来自键盘的输入更改 InputAccessoryView 中 TextField 中的文本。现在原来的 textField 仍然是第一响应者。

我已经尝试在函数 (cellForRowAt) 内创建时将 inputTextField 设置为 becomeFirstResponder,但这显然为时过早,因为键盘尚未出现。

我研究过类似的问题/答案,但没有一个涉及如何在 InputAccessoryView 中引用 textField——尤其是当来自 tableViewCell 时。

解决方法

首先我支持将其设为自定义视图而不是扩展程序,以便轻松访问文本字段

其次以您当前的方式访问它,像这样在文本字段中添加一个标签

inputTextField.tag = 33

最后像这样访问文本字段

profileDataTextField.addToolbarInputAccessoryView()
gurad let field = profileDataTextField.inputAccessoryView.viewWithTag(33) else { return }
field.becomeFirstResponder()
,

尝试延迟异步调用 becomeFirstResponder 以允许键盘初始化:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { 
    textField.becomeFirstResponder()
}