Make a UIButton inactive if no text is entered in a TextField in Swift

10,176

Solution 1

Edit:

Set myButton.userInteractionEnabled = false in the viewDidLoad or viewWillAppear.

Set your textField's delegate.

and then

func textFieldDidBeginEditing(textField: UITextField) {
   if !textField.text.isEmpty
       myButton.enable = true

   } else {
       buttonLabel.enable = false
   }
}

Solution 2

You have to set your VC as the TextFieldDelegate. So you can react on the textfields state. See this little example class:

class ViewController: UIViewController, UITextFieldDelegate {

  @IBOutlet weak var myTextField: UITextField!
  @IBOutlet weak var myButton: UIButton!

  override func viewDidLoad() {
    super.viewDidLoad()

    // Set the delegate of your textField to this class
    myTextField.delegate = self

    if myTextField.text.isEmpty {
      myButton.userInteractionEnabled = false
    }
  }
  // This method is available, because this class is now the delegate
  func textFieldDidBeginEditing(textField: UITextField) {
    myButton.userInteractionEnabled = true
  }
}

This should be quite similar to your VC.

Please note the first line, where the VC is told to conform to the TextFieldDelegate Protocol.

Solution 3

Your code should look some thing similar like below, Assuming Next button should be enabled only when we have text in one text field else you need to change the logic accordingly.

class ViewController: UIViewController, UITextFieldDelegate {

@IBOutlet weak var textField1: UITextField!
@IBOutlet weak var textField2: UITextField!
@IBOutlet weak var textField3: UITextField!
@IBOutlet weak var nextButton: UIButton!

override func viewDidLoad() {
    super.viewDidLoad()
    nextButton.userInteractionEnabled = false
    textField1.delegate = self
    textField2.delegate = self
    textField3.delegate = self
}
@IBAction func NextButtonAction(sender: UIButton)
{
    println("Next Button Tapped")
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if textField == textField1
    {
        var oldStr = textField1.text as NSString
        var newStr = oldStr.stringByReplacingCharactersInRange(range, withString: string) as NSString
        if newStr.length == 0
        {
            nextButton.userInteractionEnabled = false
        }else
        {
            nextButton.userInteractionEnabled = true
        }
    }
    return true
}
}
Share:
10,176

Related videos on Youtube

Nick89
Author by

Nick89

Great passion for digital technology and innovation. I have some experience in HTML and CSS. Learning to code Swift with no prior experience in mobile app coding. Hobbies include Snowboarding, football, and running my small business in Photography and Filming.

Updated on September 15, 2022

Comments

  • Nick89
    Nick89 over 1 year

    So my concept is simple, I have a textfield and a button labelled 'Next'. I would like the Next button to be disabled to users if they have not put anything in the textfield. To do this, I have run this code:

     @IBAction func nextButton(sender: UIButton) {
    
        if textField.text.isEmpty {
    
            buttonLabel.userInteractionEnabled = false
    
        }
     }
    

    This disables the button as i want, but the problem is, if text is then entered in the textfield, the button is still disabled. I have tried adding the "else" statement after the "if" statement to just reverse what i'm saying to see if it works, but it doesn't.

    Any help greatly appreciated.

    Nick

    MY CODE:

    import UIKit
    
    class ViewController: UIViewController, UITextFieldDelegate, UIPickerViewDataSource, UIPickerViewDelegate {
    
    func imageEffect() {
    
        // Set vertical effect for background
        var verticalMotionEffect : UIInterpolatingMotionEffect =
        UIInterpolatingMotionEffect(keyPath: "center.y",
            type: .TiltAlongVerticalAxis)
        verticalMotionEffect.minimumRelativeValue = -20
        verticalMotionEffect.maximumRelativeValue = 20
    
        // Set horizontal effect for background
        var horizontalMotionEffect : UIInterpolatingMotionEffect =
        UIInterpolatingMotionEffect(keyPath: "center.x",
            type: .TiltAlongHorizontalAxis)
        horizontalMotionEffect.minimumRelativeValue = -20
        horizontalMotionEffect.maximumRelativeValue = 20
    
        // Create group for background to combine both
        var group : UIMotionEffectGroup = UIMotionEffectGroup()
        group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]
    
        // Add both effects to your view for background
        myBackgroundView.addMotionEffect(group)
    
    }
    
    var datePickerView:UIDatePicker = UIDatePicker()
    
    @IBAction func textFieldEdited(sender: UITextField) {
    
        var datePickerView  : UIDatePicker = UIDatePicker()
        datePickerView.datePickerMode = UIDatePickerMode.Date
        sender.inputView = datePickerView
        datePickerView.addTarget(self, action: Selector("handleDatePicker:"), forControlEvents: UIControlEvents.ValueChanged)
    
        }
    
    func handleDatePicker(sender: UIDatePicker) {
        var dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "dd MMMM yyyy"
        questionTextField.text = dateFormatter.stringFromDate(sender.date)
    }
    
    var countryData = ["United Kingdom", "France", "Spain", "Germany", "Berlin", "Eygpt", "United States"]
    
    var pickerView:UIPickerView = UIPickerView()
    
    @IBOutlet var progressStatus: UIProgressView!
    
    @IBOutlet var barImage: UIImageView!
    
    @IBOutlet var questionLabel: UILabel!
    
    @IBOutlet var buttonBarImage: UIImageView!
    
    @IBOutlet var buttonLabel: UIButton!
    
    @IBOutlet var myBackgroundView: UIImageView!
    
    @IBOutlet var questionTextField: UITextField!
    
    let questions = ["Where are you going?", "What are you doing there?", "When do you go?"]
    
    var currentQuestionIndex = 0
    
    let placeholder = ["Country", "Activity", "Date"]
    
    var currentPlaceholderIndex = 0
    
    @IBAction func nextButton(sender: AnyObject) {
    
        if currentQuestionIndex == 0 {
    
            progressStatus.setProgress(0.333, animated: true)
    
        } else if currentQuestionIndex == 1 {
    
            progressStatus.setProgress(0.666, animated: true)
    
        } else {
    
            progressStatus.setProgress(1, animated: true)
    
        }
    
        // Initial setup on button press
        questionTextField.hidden = false
        barImage.hidden = false
        questionTextField.placeholder = placeholder[currentPlaceholderIndex]
        questionLabel.text = questions[currentQuestionIndex]
        questionTextField.resignFirstResponder()
    
        // Reset text field to have no text
        questionTextField.text = ""
    
        // Displays the questions in array and displays the placeholder text in the textfield
        if currentQuestionIndex <= questions.count && currentPlaceholderIndex <= placeholder.count {
    
            currentQuestionIndex++
            currentPlaceholderIndex++
            //progressStatus.setProgress(0.333, animated: true)
            buttonLabel.setTitle("Next", forState: UIControlState.Normal)
    
    
            // Animate text for questionLabel
            UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0.5, options: nil, animations: {
    
                self.questionLabel.center = CGPoint(x: -110 , y: 305 + 20)
    
                }, completion: nil)
    
        } else {
    
            //Add some logic here to run whenever the user has answered all the questions.
    
        }
    
    }
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    
        questionTextField.delegate = self
        pickerView.delegate = self
        pickerView.dataSource = self
    
        // Applies the image effect to the image in myBackgroundImage
        imageEffect()
    
        // Sets the button text
        buttonLabel.setTitle("Get started", forState: UIControlState.Normal)
    
        // Sets the question text to be blank
        questionLabel.text = ""
    
    
        // Sets placeholder text in the text field
        questionTextField.placeholder = ""
    
        // Hides the text field
        questionTextField.hidden = true
    
        // Hides the image background for the text field
        barImage.hidden = true
    
        // Sets the progress bar to nil
        progressStatus.setProgress(0, animated: true)
    
        if questionTextField.text.isEmpty {
    
            buttonLabel.userInteractionEnabled = false
        }
    
    }
    
    func textFieldDidBeginEditing(textField: UITextField) {
    
    
        buttonLabel.userInteractionEnabled = true
    
    
        switch currentQuestionIndex {
    
        case 0:
            // TODO: Add UIPickerView
            self.view.addSubview(datePickerView)
        case 2:
            // TODO: Add UIDatePicker
            self.view.addSubview(datePickerView)
    
        default:
            println("default")
        }
    }
    
    
    // resigns the keyboard when user presses the return/next key on keyboard
    
    func textFieldShouldReturn(textField: UITextField) -> Bool {
    
        questionTextField.resignFirstResponder()
    
        return true
    
    }
    
    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
    
        return 1
    }
    
    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    
        return countryData.count
    
    }
    
    func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
        return countryData[row]
    
    }
    
    func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    
        questionTextField.text = countryData[row]
        pickerView.hidden = true
    
    }
    
    
    
    
    // Resigns the keyboard if the user presses anywhere on the screen
    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    
        self.view.endEditing(true)
    }
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    }
    
  • Nick89
    Nick89 almost 9 years
    Hi, I have tried this, but it does not work, it still keeps the button disabled.
  • Jakub Truhlář
    Jakub Truhlář almost 9 years
    Sorry I missed the context, check the edit. Also consider the .enable then .userInteractionEnabled to force alpha change and let user know it is disabled
  • Nick89
    Nick89 almost 9 years
    Hi @gutenmorgenuhu. I actually share the textfield for 3 questions that are populated from an array. Each time the user presses the Next button, the next question is shown and the textfield resets itself. I added your code like you said, and it worked, but only for the first time. Does that make sense?
  • Duncan C
    Duncan C almost 9 years
    So you need to write more elaborate logic that keeps track of which text field you are collecting data from, and make your textFieldDidBeginEditing method only enable the next button based on the text field specified in the textField parameter.
  • Duncan C
    Duncan C almost 9 years
    This is the core or programming - figuring out how to apply the tools of the language to create brand-new behavior.
  • gutenmorgenuhu
    gutenmorgenuhu almost 9 years
    please show more code. then we should be able to fix that
  • Nick89
    Nick89 almost 9 years
    Thanks for your response first of all. The thing is, I have only 1 textField which is shared between the 3 questions. So how could I change the above to make it work with just one textField ? Thanks in advance
  • Shiva Kumar
    Shiva Kumar almost 9 years
    Can you provide the code how you are sharing same textfield for 3 questions, so that we can help?
  • Nick89
    Nick89 almost 9 years
    I have added my code above. I have conformed to UITextfieldDelegate and set the delegate to = self in ViewDidLoad.
  • Nick89
    Nick89 almost 9 years
    Hi, I have added my code above. I have conformed to UITextfieldDelegate and set the delegate to = self in ViewDidLoad just so you know
  • gutenmorgenuhu
    gutenmorgenuhu almost 9 years
    have you set questionTextfield.delegate = self and implemented the textFieldDidBeginEditing method?
  • gutenmorgenuhu
    gutenmorgenuhu almost 9 years
    It is very hard for me to reproduce what's going wrong at your side, because I do not have the proper storyboard. Maybe you can provide all files needed for reproducing it.
  • Nick89
    Nick89 almost 9 years
    Ideally whats file do you need to see? Can you see anything wrong with my code above? thanks
  • gutenmorgenuhu
    gutenmorgenuhu almost 9 years
    Ideally: the whole project or at least the corresponding storyboard so that alle the outlets and actions are correctly linked.
  • Nick89
    Nick89 almost 9 years
    Have you been able to see anyway of making this work with my set up? (the new code above) thanks in advance!
  • Nick89
    Nick89 almost 9 years
    @gutenmorgenuhu - I think an issue I'm running into, is that in the ViewDidLoad, we're setting: if myTextField.text.isEmpty { myButton.userInteractionEnabled = false } , and the way my app works, is that on loading the app, my textfield is hidden and has no text in it, so when setting it to be false, i can press my button to continue in the app. Is there some code that would allow the .isEmpty code to only apply when the textfield is NOT hidden? thanks Failing that, if you want i can send my files to you so you can see them all properly? Thank you
  • gutenmorgenuhu
    gutenmorgenuhu almost 9 years
    Of course I can take a look at your app. Just upload it somewhere and share the link
  • gutenmorgenuhu
    gutenmorgenuhu almost 9 years
    got it... You can delete it =)
  • gutenmorgenuhu
    gutenmorgenuhu almost 9 years
    Unfortunately, your project does compile but does not work. Clicking the "Get started" button does not do anything. Maybe you can create a new project, without any of the animations etc., which helps me reproduce your error.
  • Nick89
    Nick89 almost 9 years
    @gutenmorgenuhu - hi, i'm pretty sure the reason is, because in the ViewDidLoad, we set: if questionTextField.text.isEmpty { buttonLabel.userInteractionEnabled = false } So, on loading the app, the 'Get started' label (buttonLabel) is set to be disabled. Without this bit of code it works fine, so if you /* */ it out you'll see it becomes active.
  • gutenmorgenuhu
    gutenmorgenuhu almost 9 years
    Your code seems to work as intended. The textfields clear when I click next. What's the problem? :)