disable button when textfields are empty - objective-c

hi im a beginner to programming and have been stuck on this task for ages and seem to be getting nowhere.
basically i have several textfields that generates the input information on a different page when the user presses a button. i would like the button to be disabled until all text fields are filled with information.
so far i have this:
- (void)textFieldDidEndEditing:(UITextField *)textField
{
// make sure all fields are have something in them
if ((textfbookauthor.text.length > 0)&& (textfbookedition.text.length > 0)&& (textfbookplace.text.length > 0)&& (textfbookpublisher.text.length > 0) && (textfbookpublisher.text.length > 0) && (textfbooktitle.text.length > 0) && (textfbookyear.text.length > 0)) {
self.submitButton.enabled = YES;
}
else {
self.submitButton.enabled = NO;
}
}
the problem is the 'submitButton' is coming up with an error, what needs to go in its place?
i tried to put my button 'bookbutton'in it instead but its not working.
this is my function for the 'generate' button
-(IBAction)bookbutton:(id)sender;
{
NSString* combinedString = [NSString stringWithFormat:
#"%# %# %#.%#.%#:%#.",
textfbookauthor.text,
textfbookyear.text,
textfbooktitle.text,
textfbookedition.text,
textfbookplace.text,
textfbookpublisher.text];
BookGenerate*bookg = [[BookGenerate alloc] init];
bookg.message = combinedString;
bookg.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:bookg animated:YES];
[BookGenerate release];
}
if anybody knows how i can make it work or what i need to add please help.
thanks in advance

Make an Outlet for every UITextField and create an IBAction in your .h:
IBOutlet UITextField *textField1;
IBOutlet UITextField *textField2;
IBOutlet UITextField *textField3;
IBOutlet UIButton *button
- (IBAction)editingChanged;
Connect all the outlets and connect the IBAction to every textfield with editingChanged:
- (IBAction)editingChanged {
if ([textfield1.text length] != 0 && [textfield2.text length] != 0 && [textfield3.text length] != 0) {
[button setEnabled:YES];
}
else {
[button setEnabled:NO];
}
}
Note that you can also use [textfield.text isEqualToString:#""] and put a ! in front of it (!means 'not') to recognize the empty textField, and say 'if the textField is empty do...'
And:
- (void)viewDidLoad {
[super viewDidLoad];
[button setEnabled:NO];
}

If you have a button and you want to enable it only if there is a text in a textfield or textview, implement the follow method
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if (textView.text.length > 1 || (text.length > 0 && ![text isEqualToString:#""]))
{
self.button.enabled = YES;
}
else
{
self.button.enabled = NO;
}
return YES;
}

Few solutions are available on these posts as well
Very Similar Query
A different version of it
Key here is using (extending) UITextFieldDelegate class and it's associated function
//Need to have the ViewController extend UITextFieldDelegate for using this feature
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Find out what the text field will be after adding the current edit
let text = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
if !text.isEmpty{//Checking if the input field is not empty
button.userInteractionEnabled = true //Enabling the button
} else {
button.userInteractionEnabled = false //Disabling the button
}
// Return true so the text field will be changed
return true
}

You should use" textfield should change chracters in range" (see apple docs for uitextviewdelegate). because it updates as users type information." Textfield did end editing" only fires when the users finishes editing a textfield or hits enter. In most cases, someone will fill in the last field and leave the cursor sitting there and expect the button to become enabled...but that wont happen using "textfield did end editing" just because they entered input.
You can also do this to check the length
if([self.textfiele.text isEqualToString:#""])

In addition to having IBOutlets for each UITextField, it might be helpful to have an IBOutletCollection declared that contains all 3 text fields in an array.
#property (nonatomic, retain) IBOutletCollection(UITextField) NSArray *textFields;
Then in your implementation just #synthesize textFields and you can quickly loop the text fields it contains, checking for text.
- (IBAction)editingChanged
{
BOOL buttonShouldBeEnabled = YES;
for (UITextField *field in self.textFields)
if (!field.text.length)
buttonShouldBeEnabled = NO;
button.enabled = buttonShouldBeEnabled;
}

Related

UITextField with UIPickerView keyboard bug

I just want to ask if how can I prevent keyboard popping out when it's pressing the UITextField? I have a UITextField and UIPickerView if I press the UITextField for the first time it's fine, it's showing the UIPickerView but then after i select in the UIPickerView then press the textfield again, instead of showing the UIPickerView again it shows the keyboard? I have this method on my UITextField when you click it it shows the UIPickerView:
- (IBAction)clickText:(id)sender
{
int tag = [(UITextField*)sender tag];
self.myPicker.hidden = NO;
selectedTable = tag;
[sender resignFirstResponder];
float yy = 10;
switch (tag) {
case 0: yy = self.txtLeasename.frame.origin.y + self.myPicker.frame.size.height;
break;
case 1: yy = self.txtFeet.frame.origin.y + self.myPicker.frame.size.height;
break;
case 2: yy = self.txtInches.frame.origin.y + self.myPicker.frame.size.height;
break;
default:
break;
}
}
How can i fix this kind of bug? Thank you very much!
Implement this Method and don't forget to assign the textfield.delegate to your controller
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
// Check if the given textfield is your textfield with the date picker.
if (textField.tag == 99) {
// Then add your picker to your view
UIDatePicker *pv = [[UIDatePicker alloc] initWithFrame:CGRectMakeZero];
[self.view addSubview:pv];
// And return NO
return NO; // Return NO prevents your Textfield from showing the Keyboard
}
return YES;
}
This should work for you:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
int tag = textField.tag;
selectedTable = tag;
float yy = 10;
switch (tag) {
case 0:
self.myPicker.hidden = NO;
return NO;
case 1:
self.myPicker.hidden = NO;
return NO;
case 2:
self.myPicker.hidden = NO;
return NO;
default:
self.myPicker.hidden = YES;
return YES;
}
}
Are you looking for this?
UITextField Class Reference
inputView
The custom input view to display when the text field becomes the first responder.
#property(readwrite, retain) UIView *inputView
Discussion
If the value in this property is nil, the text field displays the standard system keyboard when it becomes first responder. Assigning a custom view to this property causes that view to be presented instead.
The default value of this property is nil.
Availability
Available in iOS 3.2 and later.
Declared In
UITextField.h
So just set the proper inputView for your UITextField in viewDidLoad or else where. Something like:
self.myTextField.inputView = self.myPicker

Can't set BecomeFirstResponder in EditingDidEnd Action

I am trying to do Error Checking for a Correct Time in a UItextField. I didn't want an error to pop up while the user is typing (To give them the chance to fix it first) so I thought I would do the Check during an EditingDidEnd Action. I setup ones for Hours, Minutes and Seconds. Here is the code I tried for inHours:
- (IBAction)inHourEditEnd:(id)sender
{
// Check to make sure value is between 0 & 23 Hours
if ([[[self inHour] text] intValue] >= 0 && [[[self inHour] text] intValue] < 24) {
[self updateDuration];
} else {
NSString *errorDescription = [NSString stringWithFormat:#"%# hours is not a valid start time. Please enter an hour between 0 and 23", [[self inHour] text]];
UIAlertView *errorMessage = [[UIAlertView alloc] initWithTitle:#"Ivalid Hour for Start Time"
message:errorDescription
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[errorMessage show];
[_inHour becomeFirstResponder];
}
}
The alert works fine but it won't go back to the textfield (inHour) after showing the alert.
It just stays on whatever textField I tapped to cause EditingDidEnd. Searching here I found a way to make the alertView send the user back to the right textbox using this code:
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
//Checks For Approval
if (buttonIndex == 0) {
[_inHour becomeFirstResponder];
}
}
But this will only work for the first box and I need to make it work with inHour, inMinute and inSeconds.
Any Suggestions how I can make this work?
Is either one of these paths in the right direction?
Thank you for any help.
If you really want to do your validation after the text field has already lost first responder status, you could add a property to your view controller to track the text field that needs to receive becomeFirstResponder:
// in your .m file, declare a class extension for "private" members
#interface MyViewController ()
#property (weak, nonatomic) UITextField *lastValidationFailureField;
#end
// add this to inHourEditEnd:
self.lastValidationFailureField = _inHour;
// use this property in alertView:clickedButtonAtIndex:
[self.lastValidationFailureField becomeFirstResponder];
self.lastValidationFailureField = nil;
Alternatively, you could prevent the user from leaving the text field. Have your view controller implement UITextFieldDelegate and set all of your text fields’ delegate outlets to your view controller. Then implement textFieldShouldEndEditing:
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
if (textField == [self inHour]) {
if ([[textField text] intValue] >= 0 && [[textField text] intValue] < 24) {
[self updateDuration];
} else {
NSString *errorDescription = ...
UIAlertView *errorMessage = ...
[errorMessage show];
// prevent the text field from even losing first responder status
return NO;
}
}
if (textField == [some someOtherTextFieldToValidate)] {
...
}
return YES;
}
I put all of the logic in a single method here for brevity, I would recommend at least some minimal refactoring of that code if you have more than a couple of text fields to validate.
You would not need your actions method such as inHourEditEnd: any more.

How to detect change in UISegmentedControl from a separate IBAction

I have a UISegmentedControl button with three segments.
In ViewController.m this is working just fine -- pressing the buttons fires the correct methods.
I have another separate UIButton that when it is pressed it needs to first CHECK the state of the UISegmentedControl (to see which button is currently pressed) and then fire a method according to that segment value.
Here is my code for that separate UIButton. The button itself is working, but I cannot seem to figure out how to GET the current value of the segment of the UISegmentedControl.
Many thanks for any assistance here.
I am new to OBJ-C. I know how to do this in VisualBasic, so answers that are on the more verbose side would be most appreciated as I need to know the 'why'. Thank you.
- (IBAction)decodeButton:(id)sender {
UISegmentedControl *segment = [UISegmentedControl alloc]; // THIS DOES NOT WORK.
if (segment.selectedSegmentIndex == 0) {
decode(textToDecode);
} else if(segment.selectedSegmentIndex == 1) {
decode1(textToDecode);
} else if(segment.selectedSegmentIndex == 2) {
decode2(textToDecode);
}
}
Here is a Tutorial using UISegmentedControl in iOS.
Just Create a Reference object and wire it properly to File Owner.
IBOutlet UISegmentedControl *segmentedControl;
Then set property
#property (strong, nonatomic) IBOutlet UISegmentedControl * segmentedControl;
Synthesize in .m file
#synthesize segmentedControl;
Now You can Access the selected index at any time.
- (IBAction)decodeButton:(id)sender {
if (segmentedControl.selectedSegmentIndex == 0) {
decode(textToDecode);
} else if(segmentedControl.selectedSegmentIndex == 1) {
decode1(textToDecode);
} else if(segmentedControl.selectedSegmentIndex == 2) {
decode2(textToDecode);
}
}
Your code alloc every time UISegmentedControl in the button press action. So use the following code for sUISegmentedControl creation and its action .
SegmentChangeView=[[UISegmentedControl alloc]initWithItems:[NSArray arrayWithObjects:#"Segment1",#"Segment2",#"Segment3",nil]];
SegmentChangeView.frame=CGRectMake(5, 44, self.view.bounds.size.width-10, 33);
SegmentChangeView.selectedSegmentIndex=0;
SegmentChangeView.segmentedControlStyle=UISegmentedControlStyleBar;
SegmentChangeView.momentary = YES;
[SegmentChangeView setTintColor:[UIColor blackColor]];
NSDictionary *attributes =[NSDictionary dictionaryWithObjectsAndKeys:[UIFont fontWithName:#"Arial" size:13],UITextAttributeFont,nil];
[SegmentChangeView setTitleTextAttributes:attributes forState:UIControlStateNormal];
[SegmentChangeView addTarget:self action:#selector(SegmentChangeViewValueChanged:) forControlEvents:UIControlEventValueChanged];
SegmentChangeView.autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleBottomMargin;
[self.view addSubview:SegmentChangeView];
-(IBAction)SegmentChangeViewValueChanged:(UISegmentedControl *)SControl
{
if (SControl.selectedSegmentIndex==0)
{
decode(textToDecode);
}
else if (SControl.selectedSegmentIndex==1)
{
decode1(textToDecode);
}
else if (SControl.selectedSegmentIndex==2)
{
decode2(textToDecode);
}
}
You should remove UISegmentedControl *segment = [UISegmentedControl alloc] ; from your code, as it allocs anew instance of your UISegmentedControl every time, instead,
create an outlet for you UISegmentController like
#property (strong, nonatomic) IBOutlet UISegmentedControl * segment;
and then later at any point in your viewcontroller.m file, you can get the currently selected segment by using
segment.selectedSegmentIndex;
Hope this make sense,
Regards
Try like this
- (IBAction)segmentedControlChanged:(id)sender
{
UISegmentedControl *s = (UISegmentedControl *)sender;
if (s.selectedSegmentIndex == 1)
{
//code
}
else
{
//code
}
}
This code means you are creating a new Object on every click
UISegmentedControl *segment = [UISegmentedControl alloc] ;
The thing you have to do take IBOutlet (Property) of your segmentedControl then I will work for you. dont create a new object in the button method. when you will make a IBOutlet it will be link with at segmentControl and your code will work that time . Thanks

How do I get a UITextField to accept focus without showing the keyboard?

I am trying to find a way to prevent the keyboard from appearing when the user taps on a TextField but could`t find a way to do it.
I tried this code after I linked my textField to delegate and still it did not work for me, the code was logging but the keyboard did appear.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
NSLog(#"BeginEditing");
return YES;
[textField resignFirstResponder];
}
When I return with NO I lose the focus from the textField, which I need.
The textFields I have are filled with values from a buttons on the same view, thats why I don't want the keyboard to appear, and at the same time I want the user to select the textField they want to fill.
if you just want user to select the textfield to fill and does not want to keyboard to show up then you can do the following:
add tag to your textfields
change the code to this:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
selectedTextFieldTag = textField.tag;
return NO;
}
use selectedTextField value to identify which textfield to fill in your code. return NO will not allow keyboard to appear.
This will help you for sure.
-(BOOL)textFieldShouldBeginEditing:(UITextField*)textField {
UIView *dummyView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
activeField.inputView = dummyView; // Hide keyboard, but show blinking cursor
return YES;
}
I tested and it is working for me. Hope this will be useful for others who have similar issue.
[textField resignFirstResponder]; will not be called because you are returning from the method before it can get called. Does that not fire a warning?
Try returning NO here or if that doesn't work, try disabling user-interaction on the text field:
[myTextField setUserInteractionEnabled:NO];
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
NSLog(#"BeginEditing");
[textField resignFirstResponder];
return YES;
}
so here you just use flag int variable to assign the value to focused textfield
define int i; flag globally in .h or .m file
after that in textField Delegate method use bellow code...
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
if (textField == yourtextField1 ) {
i=1;
}
else if (textField == yourtextField2 ) {
i=2;
}
else if (textField == yourtextField3 ) {
i=3;
}
else if (textField == yourtextField4 ) {
i=4;
}
return NO;
}
-(IBAction)yourbutton1_Clicked:(id)sender{
if( i == 1){
yourtextField1.text=yourbutton1.titleLabel.text;
}
else if ( i == 2){
yourtextField2.text=yourbutton1.titleLabel.text;
}
else if ( i == 3){
yourtextField3.text=yourbutton1.titleLabel.text;
}
else if ( i == 4){
yourtextField4.text=yourbutton1.titleLabel.text;
}
else{
NSLog(#"Please Click On TextField");//here you can put AlertView Message
}
}
and so on.......
also you can use common method with sender id of button and also tag......

Moving Onto The Next UITextField When 'Next' Is Tapped

I have an iPad application which has a sign up form within it. The form is very basic and contains only two UITextFields which are for Name & Email address.
The first TextField is for the candidates Name, When they enter their name in and press 'Next' on the keyboard I want this to automatically move to the next Email Address TextField to editing.
Any idea how I can set the next button the keyboard to jump to the next keyboard?
Thanks
You need to make your view controller the UITextField delegate, and implement the UITextField delegate method:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if (textField == nameField) {
[textField resignFirstResponder];
[emailField becomeFirstResponder];
} else if (textField == emailField) {
// here you can define what happens
// when user presses return on the email field
}
return YES;
}
Swift version:
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField == nameField {
textField.resignFirstResponder()
emailField.becomeFirstResponder()
} else if textField == emailField {
// here you can define what happens
// when user presses return on the email field
}
return true
}
You may also want to scroll your view for the emailField to become visible. If your view controller is an instance of UITableViewController, this should happen automatically. If not, you should read this Apple document, especially Moving Content That Is Located Under the Keyboard part.
Additionally to #lawicko 's answer I often change the button text to give that final finishing touch (e.g. says next when there are more fields and then done when on the last):
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
BOOL isLastTextField = //.. your logic to figure out if the current text field is the last
if (isLastTextField) {
textField.returnKeyType = UIReturnKeyDone;
} else {
textField.returnKeyType = UIReturnKeyNext;
}
}
Swift version of correct answer.
In my experience, you do not need to resignFirstResponder when switching textFields.
In this example, it's just your basic username and password textFields.
The keyboard "return key" in storyboard for username is set to "Next" and the one for password is set to "Done".
Then just connect the delegates for these two text fields and add this extension and you're pretty much done.
extension LoginViewController: UITextFieldDelegate {
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField == textFieldPassword {
self.view.endEditing(true)
} else {
textFieldPassword.becomeFirstResponder()
}
return true
}
}
A more consistent and robust way is to use NextResponderTextField
You can configure it totally from interface builder.
All you need to do is
Set the class type of your UITextField to be NextResponderTextField
Then set the outlet of the nextResponderField to point to the next responder it can be anything UITextField or any UIResponder subclass. It can be also a UIButton and the library is smart enough to trigger the TouchUpInside event of the button only if it's enabled.
Here is the library in action:
A Swift 4 extension. Just pass the array of UITextFields and it will connect each one to the next until the last one which resigns the first responder (hides the keyboard):
extension UITextField {
class func connectFields(fields: [UITextField]) {
guard let last = fields.last else { return }
// To reset the targets in case you call this method again to change the connected fields
fields.forEach { $0.removeTarget(nil, action: nil, for: .editingDidEndOnExit) }
for i in 0 ..< fields.count - 1 {
fields[i].returnKeyType = .next
fields[i].addTarget(fields[i + 1], action: #selector(UIResponder.becomeFirstResponder), for: .editingDidEndOnExit)
}
last.returnKeyType = .continue
last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), for: .editingDidEndOnExit)
}
}
- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
if (textField == self.textFieldName)
{
[self.textFieldName resignFirstResponder];
[self.textFieldPassword becomeFirstResponder];
}
else if (textField == self.textFieldPassword)
{
[self.textFieldPassword resignFirstResponder];
[self login:self];
}
return true;
}
#interface MLLoginViewController ()<UITextFieldDelegate>
#end
#implementation MLLoginViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.textFieldName.delegate = self;
self.textFieldPassword.delegate = self;
Make an outlet for the textfield, then
viewController.h
(IBAction)textFieldDoneEditing:(id)sender;
viewController.m
(IBAction)textFieldDoneEditing:(id)sender {
[textField resignFirstResponder];
if (textField == nameField) {
[emailField becomeFirstResponder];
}
}
Make the relation between (show the connections inspector > Sent Events)didEndOnExit and textFieldDoneEditing