In my app I have a view with 3 textfields. Until they are ALL filled out, I want my button to be disabled. In the storyboard I left it enabled, but then in my ViewDidLoad I added this:
if (amtYouOwe.text.length == 0 && personYouOweMoney.text.length == 0 && self.cellNum.text.length == 0)
{
saveButton.enabled = NO;
}
Even if all the fields were filled out my button was disabled..So then I tried to put it in my IBAction save button. This time I got the opposite result. No matter what my button was enabled. Even if all the textfields were blank. I believe my code is correct, I'm just trying to find the perfect place to put it....
All help is appreciated, thanks in advance.
Write a function to enable/disable saveButton as
-(void)enableDisableSave{
if (amtYouOwe.text.length == 0 && personYouOweMoney.text.length == 0 && self.cellNum.text.length == 0){
saveButton.enabled = NO;
} else {
saveButton.enabled = YES;
}
}
Write a delegate method of textField, assign your view controller as delegate to all textfield, write following delegate method and call that method in that and bingo..
- (void)textFieldDidEndEditing:(UITextField *)textField {
[self enableDisableSave];
}
You should add button enable/disable control in UITextField delegate methods. Every time a text field being edited, check all the text fields' length and change button status.
https://developer.apple.com/library/ios/documentation/uikit/reference/UITextFieldDelegate_Protocol/UITextFieldDelegate/UITextFieldDelegate.html
If you want real time checking, use this:
- (void)viewDidLoad {
[super viewDidLoad];
// ..
// your code
// ..
[self addTextChangedEvent];
[self toggleSaveButtonStatus];
}
- (void)addTextChangedEvent {
[amtYouOwe addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[personYouOweMoney addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[self.cellNum addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
}
- (void)textFieldDidChange:(UITextField *)textField {
[self toggleSaveButtonStatus];
}
- (void)toggleSaveButtonStatus {
int youOweLength = amtYouOwe.text.length;
int personYouOweLength = personYouOweMoney.text.length;
int cellNumLength = self.cellNum.text.length;
saveButton.enabled = youOweLength > 0 && personYouOweLength > 0 && cellNumLength > 0;
}
Write in .pch file
This macro does not allow white space..
#define allTrim( object ) [object stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet] ]
then write delegate method
- (void)textFieldDidEndEditing:(UITextField *)textField {
[self enableDisableSave];
}
Write a function to enable/disable saveButton as
-(void)enableDisableSave{
if ([allTrim(amtYouOwe.text) length] == 0 && [allTrim(personYouOweMoney.text) length] == 0 && [allTrim(self.cellNum.text) length] == 0){
saveButton.enabled = NO;
} else {
saveButton.enabled = YES;
}
}
Happy Coding!!!
Related
I am creating a custom delegate UIAlertView's alert:buttonClickedAtIndex: method, but it is not working properly. I am subclassing a UIView, and I have two buttons that are tagged as 0 and 1. This still does not work when I go to check the delegate for my custom view. Here the code that I did.
Custom View
- (void) buttonTouchedWithIdentifier:(NSInteger)identifier
{
if (identifier == 0) {
[self.delegate alert:self didClickButtonWithTagIdentifier:0];
}
if (identifier == 1) {
[self.delegate alert:self didClickButtonWithTagIdentifier:1];
}
}
* in my showInViewMethod *
[self.dismissButton addTarget:self action:#selector(buttonTouchedWithIdentifier:) forControlEvents:UIControlEventTouchDown];
[self.continueButton addTarget:self action:#selector(buttonTouchedWithIdentifier:) forControlEvents:UIControlEventTouchDown];
self.dismissButton.tag = 0;
self.continueButton.tag = 1;
* in my view controller *
nextLevelAlert = [[ARAlert alloc] init];
nextLevelAlert.delegate = self;
[nextLevelAlert showInView:self.view
withMessage:[NSString stringWithFormat:#"Congratulations, you have completed level %i.\nWould you like to continue?", levelNumber]
dismissButtonTitle:#"Menu"
continueButtonTitle:#"Next Level"];
- (void)alert:(ARAlert *)alert didClickButtonWithTagIdentifier:(NSInteger)tagId
{
if (alert == nextLevelAlert) {
if (tagId == 0) {
NSLog(#"User does not want to continue.");
}
}
}
Now, nextLevelAlert has the delegate set to self, and I do have the delegate declared in my view controller's class. Also, when i do the showInView... for nextLevelAlert, it DOES appear, it is recognizing what button is being pressed.
My guess is your param is not a NSInteger but the button, you should change buttonTouchedWithIdentifier like this :
- (void) buttonTouchedWithIdentifier:(id)sender
{
UIButton *button = (UIButton*)sender;
NSLog(#"buttonTouchedWithIdentifier %#",#(button.tag));
if (button.tag == 0) {
[self.delegate alert:self didClickButtonWithTagIdentifier:0];
}
if (button.tag == 1) {
[self.delegate alert:self didClickButtonWithTagIdentifier:1];
}
}
Also when comparing two objects use isEqual: instead of ==
- (void)alert:(ARAlert *)alert didClickButtonWithTagIdentifier:(NSInteger)tagId
{
if ([alert isEqual:nextLevelAlert]) {
if (tagId == 0) {
NSLog(#"User does not want to continue.");
}
}
}
This happens only on device and not on simulator..
I have two custom views and both have a UITextField in them(Child1 and Child2).
Both these views are placed on another UIView (Say viewA).
Now my requirement is such that when text is entered in one of the textfield I need to clear the other text fields content, so in the textFieldDidChange: method I inform viewA and than it iterates over its subview finds Child1 and sets its properties. But as soon as I access the textField of this Child1 to enable its userInteraction or and set its text to nil. This textfield now becomes the first responder.
I am not really sure why it does that. You can look at the below code to get more info.
Method inside viewA:
for (UIView *view in [self subviews])
{
if ([view isKindOfClass:[ChildView class]])
{
ChildView *concernedCustomerView = (ChildView *)view;
if (concernedCustomerView.typeOfCompartment == CompartmentTypeNone)
{
[concernedCustomerView.checkBoxButton setSelected:NO];
[concernedCustomerView.countSwitch setOn:NO animated:YES];
concernedCustomerView.countTextField.userInteractionEnabled = YES;
concernedCustomerView.countTextField.alpha = 1.0f;
concernedCustomerView.countTextField.text = nil;
}
}
}
Method inside custom Child View
-(void)textFieldDidChange:(id)sender
{
NSString *note = _countTextField.text;
note = [note stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
//If we are checking note for nil it should be before calling trimming white space
if (note && note.length > 0)
{
[_checkBoxButton setSelected:YES];
if (note.length == 3 && note.integerValue == 999)
{
[_countSwitch setOn:YES animated:YES];
_countTextField.userInteractionEnabled = NO;
_countTextField.alpha = 0.5f;
_countTextField.text = nil;
// [_countSwitch sendActionsForControlEvents:UIControlEventValueChanged];
}
}
else
{
[_checkBoxButton setSelected:NO];
}
if ([self.delegate conformsToProtocol:#protocol(ChildViewDelegate)] &&
[self.delegate respondsToSelector:#selector(adjustStateOfOtherControls:andCheckBoxStatus:)])
{
[self.delegate adjustStateOfOtherControls:_typeOfCompartment andCheckBoxStatus:_checkBoxButton.selected];
}
}
Do not set the view object to nil because they are alive and your controller is still active,
try to set _countTextField.text = #""; so that your textfield become empty.
Just a suggest:
1) Instead of manual iterate subviews you can assign tag to child views and uitextfields e.g:
child1View.tag = 100;
child2View.tag = 200;
...
textField1.tag = 10;
textField2.tag = 20;
then get child references from parent viewA by:
UIView *child1View = [viewA viewWithTag:100];
UIView *child2View = [viewA viewWithTag:200];
2) Set child views textfield delegate to a common viewcontroller
3) Handle one single
- (void)textFieldDidBeginEditing:(UITextField *)textField
4) Iniside this method check
if(textField.tag==10)
{
do stuff
}
else if(textfield.tag==20)
{
do other stuff
}
Hope it helps !
I want to add some strings after end editing in UITextField.
Example :
textfield 1 : user input 1000 . After focus to textfield2,I want to add "miles" to textfield1. => textfield1 : 1000 miles
And if user focus to textfield1 again, it shows only 1000 for user edit, do not have "miles".
I tried but it not work
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *) event
{
UITouch *touch = [[event allTouches] anyObject];
if ([textfield1 isFirstResponder] && (textfield1 != touch.view))
{
textfield1.text = [NSString stringWithFormat:#"miles"];
}
if ([textfield2 isFirstResponder] && (textfield2 != touch.view))
{
....
}
}
you can use the delegate methods of UITextField to do this
- (void)textFieldDidBeginEditing:(UITextField *)textField;
and
- (void)textFieldDidEndEditing:(UITextField *)textField;
Bernhard
please try this,
- (void)textFieldShouldBeginEditing:(UITextField *)textField
{
textField.text=#"";
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
textfield1.text = [NSString stringWithFormat:#"%# miles",textField.text];
}
here textFieldDidEndEditing is textField's delegate method. you need to set textfield1.delegate=self.
hope this code will help you.
Try this :-
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if(textField.tag==10) // textfield 1
{
if(![ _txt1.text rangeOfString:#"miles"].location!= NSNotFound)
{
_txt1.text = [_txt1.text stringByAppendingString:#"miles"];
}
}
else if (textField.tag == 20) // textfield 2
{
if([ _txt1.text rangeOfString:#"miles"].location!= NSNotFound)
{
_txt1.text = [_txtUser1.text stringByReplacingOccurrencesOfString:#"miles" withString:#""];
}
}
}
NOTE:- Set tag to your textfields as 10 & 20._txt1 is your textfield1 (UITextfield)
Make text global variable of NSString and then
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if(text.length>0)
{
self.textField.text =text;
}
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
text =self.txtField.text;
self.txtField.text = [NSString stringWithFormat:#"%# miles", text];
}
Set the delagate of your textfield, like below
#interface YourController : UIViewController <UITextFeildDelegate>
and then use the following methods to check
-(void)textFieldDidEndEditing:(UITextField *)textField{
if(textField....) //condition to check textfeild is
{
//do your stuff
}
}
Hope this helps
set tag for textField1 like this
self.textField1.tag = 100;
on viewDidLoad to your textField outlet, then
-(void)textFieldDidEndEditing:(UITextField *)textField
{
if (textField.tag == 100)
{
self.txtUserId.text = [NSString stringWithFormat:#"%# miles", self.txtUserId.text];
}
}
since this is a delegate method it will fire for each textField end edit event that is why you have to check with tag number. and dont forget to set the delegate
#interface YourController : UIViewController <UITextFeildDelegate>
i have four textfields. User is allowed to enter only one digit in each text field.Once the user Enters single digit its focus should be on the next textfield. i have done this part and its working fine. Now, What i want is when i remove the text from the text field then its focus should move to previous textfield. i mean if i am deleting the text(digit) from the fourth text field then its focus should move to third text field. In short on removal of text the focus should be on previous textfield.
Now, what my problem is when i remove the text from the textfield then its focus moves to previous textfield but it clears the text of that textfield(the textfield on which i have set the focus).What i want is the text should not be removed on focus.
in .h file
IBOutlet UITextField *txtPinDigit1;
IBOutlet UITextField *txtPinDigit2;
IBOutlet UITextField *txtPinDigit3;
IBOutlet UITextField *txtPinDigit4;
UITextField *currentTextField;
in .m file
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if(textField.tag==0)
{
currentTextField=txtPinDigit1;
}
else if(textField.tag==1)
{
currentTextField=txtPinDigit2;
}
else if(textField.tag==2)
{
currentTextField=txtPinDigit3;
if(isDelete)
{
textField.text=digit3;
}
}
else if(textField.tag==3)
{
currentTextField=txtPinDigit4;
}
return YES;
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if(([textField.text length]==1)&&(![string isEqualToString:#""]))
{
if(currentTextField==txtPinDigit1)
{
[txtPinDigit2 becomeFirstResponder];
}
else if(currentTextField==txtPinDigit2)
{
[txtPinDigit3 becomeFirstResponder];
}
else if(currentTextField==txtPinDigit3)
{
[txtPinDigit4 becomeFirstResponder];
}
else if(currentTextField==txtPinDigit4)
{
textField.text = [textField.text substringToIndex:MAXLENGTH-1];
//[txtPinDigit4 resignFirstResponder];
//[txtPinDigit1 becomeFirstResponder];
}
}
else if([string isEqualToString:#""])
{
isDelete=YES;
NSLog(#"replacementString:%#",string);
// textField.text=string;
if(currentTextField==txtPinDigit4)
{
textField.text=string;
digit3=nil;
[digit3 release];
digit3=[[NSString alloc] initWithFormat:#"%i",[txtPinDigit3.text intValue]];
[txtPinDigit3 becomeFirstResponder];
}
else if(currentTextField==txtPinDigit3)
{
textField.text=string;
[txtPinDigit2 becomeFirstResponder];
}
else if(currentTextField==txtPinDigit2)
{
textField.text=string;
[txtPinDigit1 becomeFirstResponder];
}
else if(currentTextField==txtPinDigit1)
{
textField.text=string;
// [txtPinDigit1 resignFirstResponder];
//[txtPinDigit1 becomeFirstResponder];
}
}
return YES;
}
in the above code MAXLENGTH=1 defined.
any help will be appreciated.
thanks in advance.
Try This code, Change shouldChangeCharactersInRange: Delegate Method
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
if ([newString length] < 1)
{
if (textField.tag==2)
{
[txtPinDigit1 performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.0];
// txt2.text=#"";
}
else if (textField.tag==3)
{
[txtPinDigit2 performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.0];
}
else if (textField.tag==4)
{
[txtPinDigit3 performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.0];
}
return YES;
} else
{
// Otherwise we cut the length of newString to 1 (if needed) and set it to the textField.
textField.text = [newString length] > 1 ? [newString substringToIndex:1] : newString;
if (textField.tag==1)
{
[textField resignFirstResponder];
[txtPinDigit2 becomeFirstResponder];
}
else if (textField.tag==2)
{
[textField resignFirstResponder];
[txtPinDigit3 becomeFirstResponder];
}
else if (textField.tag==3)
{
[textField resignFirstResponder];
[txtPinDigit4 becomeFirstResponder];
}
return NO;
}
}
Check to check length via this way and put a break point at beginning of shouldChangeCharactersInRange
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
int length = textField.text.length - range.length + string.length;
return YES;
}
I hope it will help you.
Before calling up to become first responder on filling up the 1st digit,bind the entered text inputs & the responder into dictionary...
On each previous/next condition,retrieve the information from the dictionary...The below example code is for the general previous/next custom actions(not auto though)..You just need to change the logic a bit based on the condition you prefer...
- (NSArray *) responders
{
if (_responders)
return _responders;
NSArray *textInputs = EditableTextInputsInView([[UIApplication sharedApplication] keyWindow]);
return [textInputs sortedArrayUsingComparator:^NSComparisonResult(UIView *textInput1, UIView *textInput2) {
UIView *commonAncestorView = textInput1.superview;
while (commonAncestorView && ![textInput2 isDescendantOfView:commonAncestorView])
commonAncestorView = commonAncestorView.superview;
CGRect frame1 = [textInput1 convertRect:textInput1.bounds toView:commonAncestorView];
CGRect frame2 = [textInput2 convertRect:textInput2.bounds toView:commonAncestorView];
return [#(CGRectGetMinY(frame1)) compare:#(CGRectGetMinY(frame2))];
}];
}
The below function should get called before doing previous/next auto tab.
- (Void) selectAdjacentResponder: (UISegmentedControl *) sender
{
NSArray *firstResponders = [self.responders filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIResponder *responder, NSDictionary *bindings) {
return [responder isFirstResponder];
}]];
NSLog(#"%#",firstResponders);
UIResponder *firstResponder = [firstResponders lastObject];
NSInteger offset = sender.selectedSegmentIndex == 0 ? -1 : +1;
NSInteger firstResponderIndex = [self.responders indexOfObject:firstResponder];
NSInteger adjacentResponderIndex = firstResponderIndex != NSNotFound ? firstResponderIndex + offset : NSNotFound;
UIResponder *adjacentResponder = nil;
if (adjacentResponderIndex >= 0 && adjacentResponderIndex < (NSInteger)[self.responders count])
adjacentResponder = [self.responders objectAtIndex:adjacentResponderIndex];
[adjacentResponder becomeFirstResponder];
}
Bit lengthier,but this is all i know a BIT :)..Happy coding...
My app has a registration view, I compare strings in password textfield and confirm password textfield , if they dont match I want user go back to password textfield
This question done it with using tags
UITextField jump to previous
Is there a way to accomplish this without using tags?
//call next textfield on each next button
- (BOOL) textFieldShouldReturn:(UITextField *) textField {
BOOL didResign = [textField resignFirstResponder];
if (!didResign) return NO;
if ([textField isKindOfClass:[SOTextField class]])
dispatch_async(dispatch_get_current_queue(),
^ { [[(SOTextField *)textField nextField] becomeFirstResponder]; });
return YES;
}
-(void)textFieldDidEndEditing:(UITextField *)textField{
if (textField==self.confirmPassword) {
if ([self.password.text isEqualToString:self.confirmPassword.text]) {
NSLog(#"password fields are equal");
}
else{
NSLog(#"password fields are not equal prompt user to enter correct values");
//[self.password becomeFirstResponder]; doesnt work
}
}
}
Without using tags, you could create an NSArray of textfield outlets the describes the desired ordering.
Declare and init like this ...
#property(nonatomic,strong) NSArray *textFields;
- (NSArray *)textFields {
if (!_textFields) {
// just made these outlets up, put your real outlets in here...
_textFields = [NSArray arrayWithObjects:self.username, self.password, nil];
}
return _textFields;
}
You'll need to fetch the text field that currently has focus, if there is one...
- (UITextField *)firstResponderTextField {
for (UITextField *textField in self.textFields) {
if ([textField isFirstResponder]) return textField;
}
return nil;
}
Then advance focus like this...
- (void)nextFocus {
UITextField *focusField = [self firstResponderTextField];
// what should we do if none of the fields have focus? nothing
if (!focusField) return;
NSInteger index = [self.textFields indexOfObject:textField];
// advance the index in a ring
index = (index == self.textFields.count-1)? 0 : index+1;
UITextField *newFocusField = [self.textFields objectAtIndex:index];
[newFocusField becomeFirstResponder];
}
And move focus backward like this...
- (void)previousFocus {
UITextField *focusField = [self firstResponderTextField];
// what should we do if none of the fields have focus? nothing
if (!focusField) return;
NSInteger index = [self.textFields indexOfObject:textField];
// backup the index in a ring
index = (index == 0)? self.textFields.count-1 : index-1;
UITextField *newFocusField = [self.textFields objectAtIndex:index];
[newFocusField becomeFirstResponder];
}