Make a UIButton inactive if no text is entered in a TextField in Swift
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
}
}
Related videos on Youtube
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, 2022Comments
-
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 almost 9 yearsHi, I have tried this, but it does not work, it still keeps the button disabled.
-
Jakub Truhlář almost 9 yearsSorry 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 almost 9 yearsHi @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 almost 9 yearsSo 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 almost 9 yearsThis is the core or programming - figuring out how to apply the tools of the language to create brand-new behavior.
-
gutenmorgenuhu almost 9 yearsplease show more code. then we should be able to fix that
-
Nick89 almost 9 yearsThanks 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 almost 9 yearsCan you provide the code how you are sharing same textfield for 3 questions, so that we can help?
-
Nick89 almost 9 yearsI have added my code above. I have conformed to UITextfieldDelegate and set the delegate to = self in ViewDidLoad.
-
Nick89 almost 9 yearsHi, I have added my code above. I have conformed to UITextfieldDelegate and set the delegate to = self in ViewDidLoad just so you know
-
gutenmorgenuhu almost 9 yearshave you set
questionTextfield.delegate = self
and implemented the textFieldDidBeginEditing method? -
gutenmorgenuhu almost 9 yearsIt 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 almost 9 yearsIdeally whats file do you need to see? Can you see anything wrong with my code above? thanks
-
gutenmorgenuhu almost 9 yearsIdeally: the whole project or at least the corresponding storyboard so that alle the outlets and actions are correctly linked.
-
Nick89 almost 9 yearsHave you been able to see anyway of making this work with my set up? (the new code above) thanks in advance!
-
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 almost 9 yearsOf course I can take a look at your app. Just upload it somewhere and share the link
-
gutenmorgenuhu almost 9 yearsgot it... You can delete it =)
-
gutenmorgenuhu almost 9 yearsUnfortunately, 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 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 almost 9 yearsYour code seems to work as intended. The textfields clear when I click next. What's the problem? :)