Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.0k views
in Technique[技术] by (71.8m points)

ios - How to set TextField in InputAccessoryView as First Responder [Swift]

Okay, so I have a tableView with a textField where when the user taps the textField within the tableView, the keyboard is presented with a custom InputAccessoryView. It looks like this:

enter image description here

And here is the code to create the custom InputAccessoryView, which I've tried within the cellForRowAt and on textFieldDidBeginEditing (as below) for the tableView (each row performs a different function).

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

I've created it as an extension from the 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()
}

}

The problem is, I don't know how to reference the textField ("150" in the image) within the InputAccessoryView when the keyboard appears to set it as the first responder and not the original textField.

I want the inputs from the keyboard to change the text in the TextField within the InputAccessoryView. Right now the original textField is still the first responder.

I've tried setting inputTextField to becomeFirstResponder upon creation within the function (cellForRowAt), but that's obviously too early, as the keyboard hasn't appeared yet.

I have researched the similar questions/answers, but none of them cover how to reference the textField within the InputAccessoryView--especially when coming from a tableViewCell.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Firstly I support making it a custom view instead of an extension for easy access of the textfield

Secondly to access it your current way add a tag to your textfield like this

inputTextField.tag = 33

Finally access the textfield like this

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...