I have several uitextfields within a view and I would like to disable the uibutton until all the fields have something entered into them. What's the best way of doing this?
Ideally, I'd like to do some basic validation (make sure all entries are numbers) too.
EDIT
Couldn't get the solutions below to quite work. Below is the version that I got working (cobbled together from Brad, Mike, and various other sources)
Use the UITextFieldDelegate
Create textfields in IB, and attach to the relevant IBOutlets - textField1, textField2 etc
Create and hookup the button to its relevant IBOutlet (submitButton) and IBAction (submitAction) in IB. Uncheck enabled in IB.
Create a validate method in the view controller:
-(IBAction)validateTextFields:(id)sender
{
// make sure all fields are have something in them
if ((textField1.text.length > 0) && (textField2.text.length > 0) && (textField3.text.length > 0)) {
self.submitButton.enabled = YES;
}
else {
self.submitButton.enabled = NO;
}
}
Hookup each fields 'Editing Changed' event to the validateTextFields method. (Note: The 'Value Changed' event doesn't appear to work)
Use this delegate method to limit characters (in my case to numbers, and up to one full-stop). This bit is from Erica Sadun btw.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSCharacterSet *cs;
NSString *filtered;
// Check for period
if ([textField.text rangeOfString:#"."].location == NSNotFound)
{
cs = [[NSCharacterSet characterSetWithCharactersInString:#"0123456789."] invertedSet];
filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return [string isEqualToString:filtered];
}
// Period is in use
cs = [[NSCharacterSet characterSetWithCharactersInString:#"0123456789"] invertedSet];
filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return [string isEqualToString:filtered];
}
Voila.
You will want to implement the UITextFieldDelegate Delegate on all of your textfields in a view cOntroller managing your view like so, making sure to validate your textfields after loading your view:
-(void) viewDidLoad {
textField1.delegate = self; //Note if these were created in a xib, you can do this in IB
textField2.delegate = self;
[self validateTextFields];
}
And Implement the textField:shouldChangeCharatersInRage: method to due the validation everytime the textfileds change:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
[self validateTextFields];
return YES;
}
Finally, do the actual validation and enable or disable your button as needed:
-(void) validateTextFields {
if ((textField1.text.length > 0) && textField2.text.length > 0)) {
myUIButton.enabled = YES;
}
else {
myUIButton.enabled = NO;
}
}
Set yourself to be the delegate of the textfields and handle the textFieldDidEndEditing: method. In this method you can do your validation:
- (void)textFieldDidEndEditing:(UITextField *)textField {
myButton.enabled = (myTextField1.text.length && myTextField2.length);
}
I did not like Brad's answer, as you are always one character behind. The last text field you enter text into must have at least two characters because of the way shouldChangeCharactersInRange works. Here is a solution I found to be much more helpful:
Swift:
//This line goes in viewDidLoad
field.addTarget(self, action: #selector(self.validateTextFields), forControlEvents: UIControlEvents.EditingChanged)
func validateTextFields() {
if field.text != "" {
registerButton.enabled = true
} else {
registerButton.enabled = false
}
}
Objective-C:
//This line goes in viewDidLoad
[myTextField addTarget:self
action:#selector(textFieldDidChange)
forControlEvents:UIControlEventEditingChanged];
- (void)textFieldDidChange
{
if ([self.myTextField.text isEqualToString:#""]) {
[self.button setEnabled:NO];
}
else {
[self.button setEnabled:YES];
}
}
The solution also does not require you to resign the most recent field as first responder, which I find to be useful as the button's state will change whenever your text field's text changes from an empty string to text.
A Swift 3 variant based on Jacob's example.
//
// ViewController.swift
//
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var txtTextField: UITextField!
#IBOutlet weak var btnButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Ensure that only valid changes to txtTextField enable btnButton
txtTextField.addTarget(self, action: #selector(self.validateTextField), for: UIControlEvents.editingChanged)
}
func validateTextField() {
let validValue = txtTextField.text!.trimmingCharacters(in: CharacterSet.whitespaces)
btnButton.isEnabled = validValue == "" ? false : true
}
}
Related
I have this app and a reset button to reset the values that I entered. I'm trying to get the button to be gray as long as I don't enter a valid value.
When the value is valid, it should enable and become touchable...
How can I do this?
I am using this code but it isn't working...
//Reset values
- (IBAction)resetPressed:(UIButton *)sender {
if (didPan==1) {
resetPressed.enabled = YES;
} else {
resetPressed.enabled = NO;
}
self.prozent=0;
didPan=NO;
//remove drawn intersection line
[intersectionLine removeFromSuperview];
NSLog(#"resetPressed");
}
To enable the button if it matches your criteria, use setEnabled:YES.
E.g.
UIButton *button = (UIButton *)sender;
[button setEnabled:YES];
An even better way to do this would be to use the dot notated version, like such:
button.enabled = YES;
In your condition you are using if (didPan==1) { although it would be giving the required result but it is better to use if(didPan)
secondly resetPresed is action name not the button or sender, so you should use sender instead of resetPressed
and for setting button status use [sender setEnabled:YES];//OR sender.enabled=YES;
so your code would look like this
- (IBAction)resetPressed:(UIButton *)sender {
if (didPan) {
[sender setEnabled:YES]; //OR sender.enabled=YES;
} else {
[sender setEnabled:NO]; // OR sender.enabled=NO;
}
}
If you are entering a value in a UITextField, you could set the delegate for the text field and write code for enabling/disabling inside textFieldDidEndEditing: method of the delegate object.
i.e; theButton.enabled = YES/NO
From your code it looks like you are writing code for disabling the button inside the action of that button itself which won't work if the button is disabled.
***I did solve the problem after long time of searching.
I found out that the ResetButton must have a Property
it looks like this
#property (strong, nonatomic) IBOutlet UIButton *resetButton;
Then I highlighted the button and unchecked enabled from the control(tried it before but it didn't work)
The I used button.enabled=YES and changed the colour using [resetButton setAlpha:1] for normal and [resetButton setAlpha:0.5] for not activated
Thanks guys for your help!*
if you enter the value for example in a UITextField, then use the delegate of the textfield to determine if the value is correct:
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ([textField.text isValid]) { // check if text in textfield is valid
button.enabled = YES;
} else {
button.enabled = NO;
}
return YES;
}
I want to apply validation on text field. I have two text filed and i want to enter only 0-11 value when second text field value is equal to "AM". How apply validation text filed with respect to another text field's value?
Thanks in advance...
You can achieve your design by keeping references to both text fields in your view controller.
However, it would be much more conforming to Apple's Human Interface Guidelines to use a UIPickerView for choosing from a number of items less than 12.
try this way
- (BOOL) textFieldShouldBeginEditing:(UITextField *)textField{
if(textField==self.txt1 && [self.txt2.text isEqualToString:#"AM"]){
[self.txt1 setKeyboardType:UIKeyboardTypeNumberPad];
}
return YES;
}
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if ([string isEqualToString:#""]) {
return YES;
}
if(textField==self.txt1 && [self.txt2.text isEqualToString:#"AM"]){
int no=[self.txt1.text intValue];
NSLog(#"%d",no);
int enteredno=[string intValue];
int sum=no*10+enteredno;
if (sum>11) {
return NO;
}
}
return YES;
}
Here txt1 and txt2 are first and second textfields. Set the delegate to both the textfields.
get the value from second textfiled and check then validate like
if([secTxtField.text isEqualToString:#"AM"])
{
//do the validation for the first
}
first check for only numbers here,
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
static NSCharacterSet *charSet = nil;
if(!charSet) {
charSet = [[[NSCharacterSet characterSetWithCharactersInString:#"0123456789"] invertedSet] retain];
}
NSRange location = [string rangeOfCharacterFromSet:charSet];
if(!(location.location == NSNotFound))
{
if([secTxtField.text isEqualToString:#"AM"])
{
//get the first textField input
//Conver to int
//Check for less than 11
if (pass)
{
return YES;
}
else
{
return NO;
}
}
}
return (location.location == NSNotFound);
}
I am fairly new to iphone programming and here I am facing some issues. Now in my application, I have two textfields and I want to fire an event while second textfield starts editing. now I am using following function
- (void)textFieldDidBeginEditing:(UITextField *)textField
but the thing is the event is being fired when the first textfield starts editing. It does not wait for the second text field. Is there any way I can use this function for the second textfield or may be somehow could know and pass it the value of the active textfield?
I tried writing the name of the textfield instead of (UITextField *)textField in the function but still the same result.
If I were you , I would set a tag (in Interface Builder) of the second textField to 2, or something similar. Then you can just do this:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
if (textField.tag == 2) {
//this is textfield 2, so call your method here
}
}
EDIT: Please do this to see if the method is even called:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
NSLog(#"The method was called");
}
For Swift 2.2
func textFieldDidBeginEditing(textField: UITextField) {
if textField.tag == 2 {
//this is textfield 2, so call your method here
}
}
That delegate method is gonna get called everytime the editing of ANY text field is started, so it should be you who controls what is done when this happens. I suggest you to do something like:
-(void)textFieldDidBeginEditing: (UITextField *)textField
{
if (textField == mySecondTextField)
{
//Do what you need
}
else
{
//Do nothing
}
}
I hope it helps you!
Utilitize the tag property in Interface Builder to identify your view objects in your application at runtime. It will make life a lot easier, especially when you get ready to localize your application for different languages.
In your header file for your view controller
#define kUsernameField 100
#define kPasswordField 101
#define kStartButton 300
In the view controller implementation file
- (void)textFieldDidBeginEditing:(UITextField *)textField {
switch (textField.tag) {
case kUsernameField:
// do user name stuff
break;
case kPasswordField:
// do password stuff
break;
default:
NSLog(#"No case statement for %#", [textField description]);
break;
}
}
You will find a lot of tutorial out there that use the title field of UIButton to identify them. For example:
- (IBAction)buttonTouchUp:(id)sender {
UIButton *button = (UIButton *)sender;
// don't like
if ([button.currentTitle isEqualToString:#"Start"] == NSOrderedSame) {
// because if localize your for other language then you will have
// include code for those other language
// French: Démarrer
// Spanish: Inicio
// blah blah blah
}
// better
if (button.tag == kStartButton) {
// very simple, no code changes for localization
// blah blah blah
}
}
If you are creating the object with code, you can set the tag:
button.tag = kStartButton;
// or
[button setTag:kStartButton];
You must declare first UITextFieldDelegate in your controller .h
And set the delegate of your text field. ex. myInput.delegate = self;
-(void)textFieldDidBeginEditing:(UITextField *)sender
{
if ([sender isEqual:myInput])
{
NSLog(#"test");
}
}
This works perfectly for me.
Have you checked if your second textViews delegate is set to self ? I had the same issue where I had forgotten to set the delegate of other textFields and hence the delegate method was not firing.
Please have a look to my answer in this Question, it's exactly what you're looking for
Objective C: what is a "(id) sender"?
How can I clear the field which currently has the cursor placed inside it?
I have tried:
if(textfield.isEditing)
textfield.text = #"";
This works for me, but if I select all 3 fields, and press the 'clear field button' all the fields clear Also instead of isEditing, I have tried to use tags on the UITextfields and do :
if(textfield.tag == 1)
textfield.text = #"";
but this has the same effect.
How can I solve this problem?
try one or both of these...
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.clearsOnBeginEditing = YES;
Then add delegate...
- (BOOL)textFieldShouldClear:(UITextField *)textField {
return YES;
}
Try out this in TextField's Delegate method didBeginEditing:
if ([textfield isFirstResponder]) {
textfield.text = #"";
}
Hope this helps you.
i'm trying to clear a UITextField whenever the UIControlEventEditingChanged event is being performed.
However, when I set the text to nothing, the UIControlEventEditingChanged event is being called again, and this is the way it keeps going.
This is my code:
- (void)updateText {
//other code
textfield.text = #"";
//other code
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[textfield addTarget:self action:#selector(updateText) forControlEvents:UIControlEventEditingChanged];
}
I would like to be able to set the text of the text field without it looping infinitely!
Any help appreciated.
Not sure this is the best way, but before you do your programmatic update to the textfield you could remove your UIControlEventEditingChanged listener and then add it again afterwards.
do
- (void)updateText {
//other code
if (![textfield.text isEqualToString:#""]){
textfield.text = #"";
}
//other code
}
it is probably not the most elegant solution but it is very quick and will surely work
An alternative to deregistering for the event, and reregistering is to put in a BOOL to guard against this particular recursion.
#interface MyClass : () {
BOOL clearText;
}
and in the method:
- (void)updateText {
if (clearText){
clearText = NO;
return;
}
//other code
clearText = YES;
textfield.text = #"";
//other code
}