2

With the UITextFieldDelegate, I'm disabling my UIButton "btnSignup" based on whether 3 UITextFields contain information or not. Currently, it works appropriately minus the fact that for the UIButton to reactive (run through the if statement again), I have to click off of the UITextField. The same is true for when I've typed something and I go back to delete it. The UIButton remains active until I click off of the UITextField (if I click submit without clicking elsewhere, I am able to submit, which shouldn't be the case.)

class MainVC: UIViewController, UITextFieldDelegate {

    @IBOutlet var receiveName: UITextField!
    @IBOutlet var receiveEmail: UITextField!
    @IBOutlet var receivePhone: UITextField!
    @IBOutlet var btnSignup: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.btnSignup.enabled = false
        self.btnSignup.alpha = 0.3

        self.receiveName.delegate = self
        self.receiveEmail.delegate = self
        self.receivePhone.delegate = self

    func textFieldDidBeginEditing(textField: UITextField) {

        if countElements(receiveName.text) > 0 && countElements(receiveEmail.text) > 0 && countElements(receivePhone.text) > 0 {
            self.btnSignup.enabled = true
            self.btnSignup.alpha = 1
        } else {
            self.btnSignup.enabled = false
            self.btnSignup.alpha = 0.3
        }
    }
}

I am looking for a solution that gives a more realtime effect. The function should be listening and responding if at any time the UITextField is being edited.

davidrayowens
  • 1,562
  • 2
  • 13
  • 23

4 Answers4

1

Using something close to your code I could do this as below. I added 3 class level. variables to record if the text fields had something entered. I added tags to the text fields. I changed the UITextFieldDelegate class func and tested that all three fields have text. The second you enter a field in the third field, the button lights up!

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {
    var receiveNameBool = false
    var receiveEmailBool = false
    var receivePhoneBool = false

    @IBOutlet var receiveName: UITextField!
    @IBOutlet var receiveEmail: UITextField!
    @IBOutlet var receivePhone: UITextField!
    @IBOutlet var btnSignup: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.btnSignup.enabled = false
        self.btnSignup.alpha = 0.3

        self.receiveName.delegate = self
        self.receiveEmail.delegate = self
        self.receivePhone.delegate = self

        }

    func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {

        if textField.tag == 1 {
            receiveNameBool = true
        } else if textField.tag == 2 {
            receiveEmailBool = true
        } else if textField.tag == 3 {
            receivePhoneBool = true
        }

        if receiveNameBool && receiveEmailBool && receivePhoneBool {
            self.btnSignup.enabled = true
            self.btnSignup.alpha = 1
        } else {
            self.btnSignup.enabled = false
            self.btnSignup.alpha = 0.3
        }
        return true
    }
}

Okay, in this second version, I used the textFieldDidBeginEditing func you used. Un this case the second you click inside the third field the button is enabled. In both examples you need to still write code to deal with the case if the user deletes the data they entered. But the first example above gets you what you wanted.

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {
    var receiveNameBool = false
    var receiveEmailBool = false
    var receivePhoneBool = false

    @IBOutlet var receiveName: UITextField!
    @IBOutlet var receiveEmail: UITextField!
    @IBOutlet var receivePhone: UITextField!
    @IBOutlet var btnSignup: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.btnSignup.enabled = false
        self.btnSignup.alpha = 0.3

        self.receiveName.delegate = self
        self.receiveEmail.delegate = self
        self.receivePhone.delegate = self

        }

    func textFieldDidBeginEditing(textField: UITextField) {

        if textField.tag == 1 {
            receiveNameBool = true
        } else if textField.tag == 2 {
            receiveEmailBool = true
        } else if textField.tag == 3 {
            receivePhoneBool = true
        }

        if receiveNameBool && receiveEmailBool && receivePhoneBool {
            self.btnSignup.enabled = true
            self.btnSignup.alpha = 1
        } else {
            self.btnSignup.enabled = false
            self.btnSignup.alpha = 0.3
        }
    }
}
Steve Rosenberg
  • 19,348
  • 7
  • 46
  • 53
0

For this you can use text fields delegate method stringByReplacingCharactersInRange.

enum tags: Int{

case receiveNameTag = 1, receiveEmailTag, receivePhoneTag


}

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

@IBOutlet var receiveName: UITextField!
@IBOutlet var receiveEmail: UITextField!
@IBOutlet var receivePhone: UITextField!
@IBOutlet var btnSignup: UIButton!

// here first assign the true because all the textfields are empty
var isReceiveNameTextFieldEmpty = true
var isReceiveEmailTextFieldEmpty = true
var isReceivePhoneTextFieldEmpty = true

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    self.btnSignup.enabled = false
    self.btnSignup.alpha = 0.3


    //here adding tags to the individual textfield and this is the best way to use tags
    receiveName.tag = tags.receiveNameTag.toRaw()
    receiveEmail.tag = tags.receiveEmailTag.toRaw()
    receivePhone.tag = tags.receivePhoneTag.toRaw()

    self.receiveName.delegate = self
    self.receiveEmail.delegate = self
    self.receivePhone.delegate = self

}

func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {

    textField.text = (textField.text as NSString).stringByReplacingCharactersInRange(range,
        withString:string)

    //checking whether textfield is empty or not
    if countElements(textField.text) > 0 {

        if textField.tag == tags.receiveNameTag.toRaw() {
            isReceiveNameTextFieldEmpty = false
        }
        if textField.tag == tags.receiveEmailTag.toRaw() {
            isReceiveEmailTextFieldEmpty = false
        }
        if textField.tag == tags.receivePhoneTag.toRaw() {
            isReceivePhoneTextFieldEmpty = false
        }

    }
    else {

        if textField.tag == tags.receiveNameTag.toRaw() {
        isReceiveNameTextFieldEmpty = true
        }
        if textField.tag == tags.receiveEmailTag.toRaw() {
            isReceiveEmailTextFieldEmpty = true
        }
        if textField.tag == tags.receivePhoneTag.toRaw() {
            isReceivePhoneTextFieldEmpty = true
        }

    }

    //if atleast one textfield is empty disable button other wise enable
    if isReceiveNameTextFieldEmpty && isReceiveEmailTextFieldEmpty && isReceivePhoneTextFieldEmpty {
        self.btnSignup.enabled = false
        self.btnSignup.alpha = 0.3
    }
    else {
        self.btnSignup.enabled = true
        self.btnSignup.alpha = 1
    }


}

}

Anjaneyulu Battula
  • 1,910
  • 16
  • 33
0

I had a similar problem with one of my apps. It happened for me because the delegate was called on a background thread, which wouldn't update the view immediately. You need to sync all of your ui changes to the main thread. See the below code:

class MainVC: UIViewController, UITextFieldDelegate {

    @IBOutlet var receiveName: UITextField!
    @IBOutlet var receiveEmail: UITextField!
    @IBOutlet var receivePhone: UITextField!
    @IBOutlet var btnSignup: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.btnSignup.enabled = false
        self.btnSignup.alpha = 0.3

        self.receiveName.delegate = self
        self.receiveEmail.delegate = self
        self.receivePhone.delegate = self

    func textFieldDidBeginEditing(textField: UITextField) {
        dispatch_sync(dispatch_get_main_queue(), {
            if countElements(self.receiveName.text) > 0 && countElements(self.receiveEmail.text) > 0 && countElements(self.receivePhone.text) > 0 {
                self.btnSignup.enabled = true
                self.btnSignup.alpha = 1
            } else {
                self.btnSignup.enabled = false
                self.btnSignup.alpha = 0.3
            }
        })
    }
}

Also, if your countElements function is local to your class, add a self. in front of the call.

mtaylor
  • 1,130
  • 1
  • 8
  • 6
0

It can be solved using textField(_:shouldChangeCharactersInRange:replacementString:) just define this method with your definition as follows:

func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {

        if countElements(receiveName.text) > 0 && countElements(receiveEmail.text) > 0 && countElements(receivePhone.text) > 0 {
            self.btnSignup.enabled = true
            self.btnSignup.alpha = 1
        } else {
            self.btnSignup.enabled = false
            self.btnSignup.alpha = 0.3
        }
        return true
  }

And I consider countElements() is calculating the length of the string.

Shanmugaraja G
  • 2,778
  • 4
  • 31
  • 47