I want to change the UITextInputTraits of a keyboard while it is in use....
My ideal code would look something like this:
- (IBAction)nameTextDidChange:(UITextField *)sender {
if ([sender.text isEqualToString:#""]) {
sender.returnKeyType = UIReturnKeyDone;
} else {
sender.returnKeyType = UIReturnKeySearch;
}
}
So... I have a different 'Return' button for an empty string as I do a string with some text in. The code I posted above doesn't work, the keyboard retains it's original text input traits.
Any ideas anyone, or is this never going to work no-matter how hard I try?
Cheers!
Nick.
Thanks to Deepak, this is the code I actually used:
if ([sender.text isEqualToString:#""]) {
sender.returnKeyType = UIReturnKeyDone;
[sender resignFirstResponder];
[sender becomeFirstResponder];
} else if (sender.returnKeyType == UIReturnKeyDone) {
NSString *cachedLetter = sender.text;
sender.returnKeyType = UIReturnKeySearch;
[sender resignFirstResponder];
[sender becomeFirstResponder];
sender.text = cachedLetter;
}
You can make this work by adding the following lines at the end of the method.
if ([textField.text isEqualToString:#""]) {
textField.returnKeyType = UIReturnKeyDone;
[textField resignFirstResponder];
[textField becomeFirstResponder];
} else if (textField.returnKeyType == UIReturnKeyDone) {
textField.returnKeyType = UIReturnKeySearch;
[textField resignFirstResponder];
[textField becomeFirstResponder];
}
This should work.
You basically flip it on and off so that the text input changes. The second if is to make sure you flip only if needed.
[textField reloadInputViews] seems to do the trick...
resignFirstResponder/becomeFirstResponder & reloadInputViews have some caveats. See stackoverflow.com/questions/5958427/…. These change the keyboard back to its initial state. So if the user had toggled to one of the other keyboard layouts (numbers, punctuation, etc), that state will get lost. I've never found a good solution.
Related
I am creating a "sign in" and "create account" form for my iOS app. I successfully implemented the scrolling up of the UITextField when it is hidden. However, now that I implemented the "next" button the "UIKeyboardDidShowNotification" is not called because the keyboard is never dismissed. I need the keyboardWasShow method called so I can check if the active UITextField is hidden or not.
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// If active text field is hidden by keyboard, scroll it so it's visible
// Your application might not need or want this behavior.
CGRect aRect = self.view.frame;
CGPoint pointInSuperview = [self.view convertPoint:self.activeField.frame.origin fromView:self.scrollView];
aRect.size.height -= kbSize.height;
//added 10 to y axis because tip of origin was outside of keyboard
pointInSuperview.y +=20;
if (!CGRectContainsPoint(aRect, pointInSuperview)) {
CGPoint scrollPoint = CGPointMake(0.0, pointInSuperview.y - (kbSize.height -15));
NSLog(#"it is not in the rect");
[self.scrollView setContentOffset:scrollPoint animated:YES];
}
}
and I have an observer
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
and after I implemented my Next button (see below) the keyboardWasShown method is not called so it never checks if the active UITextField is hidden.
//functionality for next action
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if (textField == self.emailAddress) {
[self.fullName becomeFirstResponder];
[self keyboardWasShown:(NSNotification*)UIKeyboardDidShowNotification];
}
else if (textField == self.fullName) {
[self.password becomeFirstResponder];
}
else if (textField == self.password) {
[self.confirmPassword becomeFirstResponder];
}
[textField resignFirstResponder];
return YES;
}
What would be the best approach to call keyboardWasShown when the user clicks the Next button? I tried making it a public method but I kept getting errors when I tried to call it manually.
One way to avoid this is to resign the responder prior to setting the next responder, which will ensure that the keyboardWasShown notification was called. For example, based on your code you could use the following:
...
else if (textField == self.fullName) {
[self.fullName resignFirstResponder];
[self.password becomeFirstResponder];
}
...
Whilst this might seem odd, it should be noted that the keyboard doesn't actually disappear/reappear.
You may want to look into this
If your fields arent in a table the same sort of logic can apply to other cases.
I have an IBAction that is called when someone is done entering text in a field. I then validate the input. If I have determined there is an error, I display a message and want the user to enter into that same field again. Rather than make them select the text field to bring the keyboard up (which works fine) I want to just leave the keyboard displayed.
I am doing [SymbolEntered becomeFirstResponder]; as the last statement in my IBAction, but the keyboard still goes away. Am I putting that in the wrong place? Any help would be appreciated. Thanks.
- (IBAction)textFieldDoneEditing:(id)sender {
DebugMsg.text = nil;
DebugMsg2.text = nil;
DebugMsg3.text = nil;
NSLog (#"done editing");
NSLog (#"%#", SymbolEntered.text);
if ([SymbolEntered.text isEqualToString:nil])
{
Result.textColor = [UIColor redColor];
Result.text = #"You must enter a symbol!";
[SymbolEntered becomeFirstResponder];
}
else
{
if ([SymbolEntered.text isEqualToString:
[NSString stringWithCString:elements_table2[el_tbl_idx-1].element_symbol]])
{
correct_count++;
Result.textColor = [UIColor greenColor];
Result.text = #"Correct!";
Score.hidden = FALSE;
Score.text = [NSString stringWithFormat:#"Score: %d out of %d - %d Percent", correct_count, el_count+1,
(correct_count*100)/(el_count+1)];
GetNextElementButton.hidden = FALSE;
SymbolEntered.enabled = FALSE;
el_count++;
attempts = max_tries + 1;
}
else
{
Score.hidden = TRUE;
Result.textColor = [UIColor redColor];
if (attempts < max_tries)
{
if (attempts+1 == max_tries)
{
Result.text = #"Sorry, one more try -";
}
else
{
Result.text = #"Sorry, try again - ";
}
GetNextElementButton.hidden = TRUE;
attempts++;
}
else
{
Result.text = [[NSString alloc] initWithFormat: #"Sorry. The correct answer is %#",
[NSString stringWithCString:elements_table2[el_tbl_idx-1].element_symbol]];
Score.hidden = FALSE;
Score.text = [NSString stringWithFormat:#"Score: %d out of %d - %d Percent", correct_count, el_count+1, (correct_count*100)/(el_count+1)];
GetNextElementButton.hidden = FALSE;
SymbolEntered.enabled = FALSE;
el_count++;
}
}
}
[SymbolEntered becomeFirstResponder];
NSLog (#"end of textfieldoneediting");
}
You can do your validation in the UITextField textFieldShouldEndEditing: delegate method instead. If you return NO from that callback, the text field will remain first responder and the keyboard won't go away. (You'll have to make your controller object the text field's delegate if it isn't already, of course.)
Try calling the [textField becomeFirstResponder] sometime later? Also make sure the UITextField pointer is not nil or something. For more help please show some of your code, it's very hard to tell where the problem is like this.
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
Try This it will resign the keyboard.
hi
i am using a series of textfields in a row in my application and my requirement is the textfield should accept only one character.if a user enters second character no action should be performed.
i implemented the delegate method as below
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string{
if ([cellTextField.text length]>=MAXLENGTH && range.length==0) {
textField.text=[cellTextField.text substringToIndex:MAXLENGTH-1];
return NO;
}
else {
return YES;
}
but my requirement is not being filled using the above code.
my next requirement is if a user continues entering a second character, the character should be placed in the consecutive textField(imagine crossword or scramble application). please help me in both scenarios if possible else solution for first requirement is also thankful.
thank you,
dinakar
The following code solved this for me.
Make sure you check for the "\b" (Backspace escape character) so that the user can still erase.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if ([textField.text length] >= MAXLENGTH && ![string isEqualToString:#"\b"])
return NO;
return YES;
}
As far as your second requirement goes it's really not too hard. Just add a few lines of code into the above if-statement:
nextTextField.text = [nextTextField.text stringByAppendingString:string];
This should add whatever text you just typed in to the end of your next text field. You might also want to change the way backspace is handled. Something like:
if ([string isEqualToString:#"\b"])
nextTextField.text = [nextTextField.text substringToIndex:[nextTextField.text length]-1];
Adding that code inside the above if statement as well should allow you to delete the character at the end of the complete string (at the end of the string in the next text field).
EDIT: Here's the code I use to create the field.
titleInput = [[UITextField alloc] initWithFrame:(CGRect){40,145,400,30}];
titleInput.borderStyle = UITextBorderStyleRoundedRect;
titleInput.delegate = self;
[self addSubview:titleInput];
Cheers
if(cellTextField.text.length >= MAXLENGTH)
{
[cellTextField2 becomeFirstResponder]
}
This sets the focus to be the second text field
check in below functions for the number of character in your UITextField;
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
if the number of character in you text field is more than one just return NO;
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if(mytextField1 == textField && [mytextField1.text length] >= 1)
{
[mytextField1 becomeFirstResponder];
return NO;
}
else if(mytextField2 == textField && [mytextField2.text length] >= 1)
{
[mytextField3 becomeFirstResponder];
return NO;
}
-------------------------------
-------------------------------
else if(mytextField8 == textField && [mytextField8.text length] >= 1)
{
[mytextField1 becomeFirstResponder];
return NO;
}
return YES;
}
In my application, I'm forcefully showing/hiding keyboard by making textview becomefirstresponder and resignfirstresponder and also setting textview editable YES and NO respectively.
But after hiding keyboard if I tap on textview, the keyboard doesn't show up. I'm setting textview delegate to self. And the delegate method is firing up the first time but not after that.
EDIT: I'm using the following code which I am writing for a custom button-tap and checking flags to check keyboard is in hidden state or otherwise:
switch(rotationFlag)
{
case 0:
{
[self hideKeyboard];
rotationFlag = 1;
break;
}
case 1:
{
[self showKeyboard];
rotationFlag = 0;
break;
}
}
-(void)hideKeyboard{
[txtVwForPosts setEditable:FALSE];
[txtVwForPosts resignFirstResponder];
}
-(void)showKeyboard{
[txtVwForPosts setEditable:TRUE];
[txtVwForPosts becomeFirstResponder];
}
What is it that I'm doing wrong?
Can anybody please help?
Thanx in advance.
I'm not sure whats wrong with your code but following is a code which i wrote for same purpose:
-(IBAction)hideShowKeyboard:(id)sender
{
if([tv isFirstResponder])
{
[tv resignFirstResponder];
}
else
{
[tv becomeFirstResponder];
}
}
THis was the action for the button. and tv is the TextView outlet. But this view doesn't detect tap on the textview after the keyboard is hidden. If you want to detect taps just avoid setting the editable property to NO.
switch(rotationFlag)
{
case 0:
{
[self hideKeyboard];
rotationFlag = 1;
break;
}
case 1:
{
[self showKeyboard];
rotationFlag = 0;
break;
}
}
-(void)hideKeyboard
{
[txtVwForPosts resignFirstResponder];
}
-(void)showKeyboard
{
[txtVwForPosts becomeFirstResponder];
}
I've been researching this for a few days now, and would appreciate a little help. Is there any way to generate a multi-line UITextField like Apple use in the SMS application? The useful thing about this control is that it has the 'sunk' appearance that makes it clear that it is a text entry box, but at the same time, it expands on each new-line character.
Failing that, if I'm forced to use a UITextView, can anyone advise how best to dismiss the keyboard ? Both the 'Done' and the 'Go' buttons just appear to generate newline characters ('\n'). This seems wrong to me - surely at least one of these should generate a different character, so that I can still allow for newline characters, but also dismiss my keyboard on a specific key press.
Am I missing something simple here ?
Thanks in advance :)
Maybe you can build upon a class I wrote? It's the same as tttexteditor, without the ugly glitches: http://www.hanspinckaers.com/multi-line-uitextview-similar-to-sms
An old question, but after several hours I've figured out how to make it the same perfectly as in Instagram (it has the best algorithm among all BTW)
Initialize with this:
// Input
_inputBackgroundView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, size.height - _InputBarHeight, size.width, _InputBarHeight)];
_inputBackgroundView.autoresizingMask = UIViewAutoresizingNone;
_inputBackgroundView.contentMode = UIViewContentModeScaleToFill;
_inputBackgroundView.userInteractionEnabled = YES;
[self addSubview:_inputBackgroundView];
[_inputBackgroundView release];
[_inputBackgroundView setImage:[[UIImage imageNamed:#"Footer_BG.png"] stretchableImageWithLeftCapWidth:80 topCapHeight:25]];
// Text field
_textField = [[UITextView alloc] initWithFrame:CGRectMake(70.0f, 0, 185, 0)];
_textField.backgroundColor = [UIColor clearColor];
_textField.delegate = self;
_textField.contentInset = UIEdgeInsetsMake(-4, -2, -4, 0);
_textField.showsVerticalScrollIndicator = NO;
_textField.showsHorizontalScrollIndicator = NO;
_textField.font = [UIFont systemFontOfSize:15.0f];
[_inputBackgroundView addSubview:_textField];
[_textField release];
[self adjustTextInputHeightForText:#""];
Fill UITextView delegate methods:
- (void) textViewDidBeginEditing:(UITextView*)textView {
[self adjustTextInputHeightForText:_textField.text];
}
- (void) textViewDidEndEditing:(UITextView*)textView {
[self adjustTextInputHeightForText:_textField.text];
}
- (BOOL) textView:(UITextView*)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text {
if ([text isEqualToString:#"\n"])
{
[self performSelector:#selector(inputComplete:) withObject:nil afterDelay:.1];
return NO;
}
else if (text.length > 0)
{
[self adjustTextInputHeightForText:[NSString stringWithFormat:#"%#%#", _textField.text, text]];
}
return YES;
}
- (void) textViewDidChange:(UITextView*)textView {
[self adjustTextInputHeightForText:_textField.text];
}
And the trick is...
- (void) adjustTextInputHeightForText:(NSString*)text {
int h1 = [text sizeWithFont:_textField.font].height;
int h2 = [text sizeWithFont:_textField.font constrainedToSize:CGSizeMake(_textField.frame.size.width - 16, 170.0f) lineBreakMode:UILineBreakModeWordWrap].height;
[UIView animateWithDuration:.1f animations:^
{
if (h2 == h1)
{
_inputBackgroundView.frame = CGRectMake(0.0f, self.frame.size.height - _InputBarHeight, self.frame.size.width, _InputBarHeight);
}
else
{
CGSize size = CGSizeMake(_textField.frame.size.width, h2 + 24);
_inputBackgroundView.frame = CGRectMake(0.0f, self.frame.size.height - size.height, self.frame.size.width, size.height);
}
CGRect r = _textField.frame;
r.origin.y = 12;
r.size.height = _inputBackgroundView.frame.size.height - 18;
_textField.frame = r;
} completion:^(BOOL finished)
{
//
}];
}
Facebook has released an open-source package called Three20 that has a multi-line text field. You can use this pretty easily for an expanding text field.
As for the "Done" button, you can set your view controller as a UITextFieldDelegate. Then use this method:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
// Do whatever you want for your done button
return YES;
}
In the case of Three20, use this method of TTTextEditorDelegate:
- (BOOL)textFieldShouldReturn:(TTTextEditor *)textField {
// Do whatever you want for your done button
return YES;
}
Well, I had a similar problem, and what I ended up using is actually create a disabled UITextField as the background and a UITextView above it to get the input... It sucks that iPhone API cannot have this by default. Also note that this does not auto-expand, but you can do this if you want by handling the textViewDidChange:
As for handling the return key, try implementing the following method from the UITextViewDelegate:
- (void)textViewDidChange:(UITextView *)inTextView {
NSString *text = inTextView.text;
if ([text length] > 0 && [text characterAtIndex:[text length] -1] == '\n') {
inTextView.text = [text substringToIndex:[text length] -1]; // remove last return from text view
[inTextView resignFirstResponder]; // hide keyboard
}
}
(void)textEditorDidBeginEditing:(TTTextEditor *)textEditor {
And
(void)textEditorDidEndEditing:(TTTextEditor *)textEditor {
might be what you're looking for. Enjoy!