UITextField doesn't end editing when Button clicked( delegate textFieldDidEndEditing )
Asked Answered
W

4

10

I have two textFields on the screen and a Submit button. User inputs details in first textField and then the second one.

My requirement is to end the editing when Submit button is clicked and print the user inputs in these textFields.I am having issues printing the second textField's value, as the editing never seems to end when the user clicks the Submit button.

Here is my code. Appreciate your help on this issue (I have added the textfield delegate)

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    var firstName = ""
    var lastName = ""

    @IBOutlet var buttonUI: UIButton!
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func Submit(sender: UIButton) {

        print(firstName)
        print(lastName)

    }

    func textFieldDidEndEditing(textField: UITextField) {

        switch textField.tag {

        case 1:
              firstName = textField.text!
            print(firstName)
        case 2:

            lastName = textField.text!
            print(lastName)

        default: break
        }

    }


}
Walke answered 16/12, 2015 at 22:3 Comment(0)
H
22

Within your ViewController class, for each textfield, create an @IBOutlet property by Ctrl-dragging each text field from the storyboard to your code

@IBOutlet weak var textFieldFirst: UITextField!
@IBOutlet weak var textFieldSecond: UITextField!

Also create a private UITextField property to hold the (possibly) current (/most recently used) text field.

private var currentTextField: UITextField?

Override the viewDidLoad method of your UIViewController subclass to initialize the delegates for the two "public" text field instances

override func viewDidLoad() {
    super.viewDidLoad()

    // Handle the user input in the text fields through delegate callbacks (and set tags)
    textFieldFirst.delegate = self
    textFieldFirst.tag = 1
    textFieldSecond.delegate = self
    textFieldSecond.tag = 2
}

Moreover, use the two textFieldShouldReturn(...) and textFieldDidBeginEditing(...) methods of the UITextFieldDelegate to resign the (active) text fields status's as first responder and to update the currentTextField reference, respectively.

// UITextFieldDelegate
func textFieldShouldReturn(textField: UITextField) -> Bool {
    // User finished typing (hit return): hide the keyboard.
    textField.resignFirstResponder()
    return true
}

func textFieldDidBeginEditing(textField: UITextField) {
    currentTextField = textField
}

Finally, resign any possibly current text field as first responder, in case submit is pressed in-middle-of editing

@IBAction func Submit(sender: UIButton) {
    if let currentTextField = currentTextField {
        currentTextField.resignFirstResponder()
    }
    print(firstName)
    print(lastName)
}

With this, your view controller should work as intended.


To summarize: after the additions and modifications above, your ViewController class should look like

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    // Properties
    @IBOutlet weak var textFieldFirst: UITextField!
    @IBOutlet weak var textFieldSecond: UITextField!
    private var currentTextField: UITextField?
    var firstName = ""
    var lastName = ""

    @IBOutlet var buttonUI: UIButton!
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // Actions
    @IBAction func Submit(sender: UIButton) {
        if let currentTextField = currentTextField {
            currentTextField.resignFirstResponder()
        }
        print(firstName)
        print(lastName)
    }

    // viewDidLoad
    override func viewDidLoad() {
        super.viewDidLoad()

        // handle the user input in the text fields through delegate callbacks
        textFieldFirst.delegate = self
        textFieldSecond.delegate = self

        // tags
        textFieldFirst.tag = 1
        textFieldSecond.tag = 2
    }

    // UITextFieldDelegate
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        // User finished typing (hit return): hide the keyboard.
        textField.resignFirstResponder()
        return true
    }

    func textFieldDidBeginEditing(textField: UITextField) {
        currentTextField = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        switch textField.tag {
        case 1:
            firstName = textField.text!
            print(firstName)
        case 2:
            lastName = textField.text!
            print(lastName)
        default: break
        }
    }
}
Hayott answered 16/12, 2015 at 22:26 Comment(8)
Thanks for the answer, but as I just commented to the answer above, I was avoiding cntrl dragging text fields to the View Controller, as in my actual member registration page there are 6 text fields( i just posted a sample version with 2 text fields in my question) and I really dont want to connect outlets to each one of them. If there is any other way without connecting the outlets kindly let me know, much appreciatedWalke
@Naishta: you do need some UITextView instances that can communicate with your view; if not, your text views are "floating by themselves" in the view space, with no contact with your controller.Hayott
brilliant thanks for the detailed explanation, I will try your suggestions and accept the answer soon/ update you if i have issuesWalke
@Naishta: one option, however, would be to create your own custom subclass of UIView, and fill a single instance of this class with your 6 instances of UITextField:s. This way, you'd only need one outlet from storyboard -> controller (view->controller); the one from your custom UIView subclass. You could access the 6 UITextField instances (within your custom class instance) via your class interface (proper methods for these). This will be a bit trickier for the UITextField delegates though, but surely some good practice for developing your swift coding.Hayott
that worked. Thanks very much for such descriptive answer and making me understand the issue. I connected outlets to the text fields and checking the last text field to dismiss editing which is what I was looking for. Great, didnt know SO is such powerful when I get stuck:-)Walke
Your welcome. Also, if you feel up for up longer up the road, do try the container approach I just mentioned, good practice for custom UIView classes :)Hayott
sure I will , I have just started Swift and once I am comfortable getting the functionality working I will revisit and implement the best practises for sureWalke
resignFirstResponder() helped.Amie
A
1

What do you mean by

I am having issues printing the 2nd textfield's user inputs, as the editing never gets ended when user clicks the Submit.

Why not just read the values in textfields when the users presses submit? Make sure your outlets and delegates are correct.

Make an action to your button Touch up inside and in that button you´ll read the values:

firstName = textFieldOne.text
lastName = textFieldTwo.text
Adamic answered 16/12, 2015 at 22:8 Comment(1)
Thanks, but I am trying to avoid connecting the Outlets for each textfield, as the above scenario is just a sample, and the one I am actually trying is with 6 text fields( like a Member Registraton page). I really dont want to connect these 6 text fields to View Controller. Is there any other way without Cntrl+dragging the outlets and just by using delegates?Walke
H
1

If still any one needs it. You can add

view.endEditing(true) 

inside your button outside the cell

and add this inside your tableviewCell

func textFieldShouldReturn(textField: UITextField) -> Bool {
        // User finished typing (hit return): hide the keyboard.
        textField.resignFirstResponder()
        return true
}
Hormone answered 8/11, 2021 at 4:0 Comment(0)
W
0

implemented @dfri's suggestion that worked !!!

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

var firstName = ""
var lastName = ""

@IBOutlet var NameTextField: UITextField!
@IBOutlet var PasswordTextField: UITextField!

@IBOutlet var buttonUI: UIButton!
override func viewDidLoad() {
    super.viewDidLoad()
}

@IBAction func Submit(sender: UIButton) {
  
    PasswordTextField.resignFirstResponder() // this works and dismisses the editing ( outlets need to be connected aswell for the textfields)
    print(firstName)
    print(lastName)
    
}

func textFieldDidEndEditing(textField: UITextField) {
    
    switch textField.tag {
        
    case 1:
          firstName = textField.text!
        print(firstName)
    case 2:
        
        lastName = textField.text!
        print(lastName)
  
    default: break
    }
    
}


}
Walke answered 16/12, 2015 at 23:21 Comment(1)
It's great that it works, and always good to have a somewhat new face at stack overflow, bu note that you shouldn't add answers to your own questions (unless no one else have found and answer and you manage to answer your own question at that point). So you should probably delete this answer. Another note: note that IF the user for some reason chooses to first enter his/her password, and then enter username, then your implementation above will not work as intended (therefor in my solution I added an additional private text field var to hold most recently edited textfield). Just a note :)Hayott

© 2022 - 2024 — McMap. All rights reserved.