6

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
  • 2,948
  • 10
  • 31
  • 50

4 Answers4

4

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
   }
}
Jakub Truhlář
  • 20,070
  • 9
  • 74
  • 84
  • Hi, I have tried this, but it does not work, it still keeps the button disabled. – Nick89 May 13 '15 at 22:06
  • 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 – Jakub Truhlář May 13 '15 at 22:07
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.

gutenmorgenuhu
  • 2,312
  • 1
  • 19
  • 33
  • 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? – Nick89 May 13 '15 at 22:24
  • 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 May 13 '15 at 23:57
  • This is the core or programming - figuring out how to apply the tools of the language to create brand-new behavior. – Duncan C May 13 '15 at 23:58
  • please show more code. then we should be able to fix that – gutenmorgenuhu May 14 '15 at 06:57
  • Hi, I have added my code above. I have conformed to UITextfieldDelegate and set the delegate to = self in ViewDidLoad just so you know – Nick89 May 14 '15 at 17:32
  • have you set `questionTextfield.delegate = self` and implemented the textFieldDidBeginEditing method? – gutenmorgenuhu May 14 '15 at 17:44
  • 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. – gutenmorgenuhu May 14 '15 at 20:01
  • Ideally whats file do you need to see? Can you see anything wrong with my code above? thanks – Nick89 May 14 '15 at 21:10
  • Ideally: the whole project or at least the corresponding storyboard so that alle the outlets and actions are correctly linked. – gutenmorgenuhu May 15 '15 at 04:15
  • @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 – Nick89 May 16 '15 at 11:42
  • Of course I can take a look at your app. Just upload it somewhere and share the link – gutenmorgenuhu May 16 '15 at 11:44
  • got it... You can delete it =) – gutenmorgenuhu May 18 '15 at 07:04
  • 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. – gutenmorgenuhu May 18 '15 at 07:45
  • @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. – Nick89 May 18 '15 at 20:21
  • Your code seems to work as intended. The textfields clear when I click next. What's the problem? :) – gutenmorgenuhu May 19 '15 at 08:28
1

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
}
}
Shiva Kumar
  • 389
  • 3
  • 22
  • 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 – Nick89 May 14 '15 at 07:45
  • Can you provide the code how you are sharing same textfield for 3 questions, so that we can help? – Shiva Kumar May 14 '15 at 09:47
  • I have added my code above. I have conformed to UITextfieldDelegate and set the delegate to = self in ViewDidLoad. – Nick89 May 14 '15 at 17:31
  • Have you been able to see anyway of making this work with my set up? (the new code above) thanks in advance! – Nick89 May 15 '15 at 23:26
0

Event should respond to editing changed, Swift version

@IBAction func editingChanged(textfield: UITextField) {

        myButton.enabled = textfield.text?.characters.count > 0
}
Swapnil
  • 1,858
  • 2
  • 22
  • 49