I have multiple textfields on a UIView.
I resign for a previous textField in textFieldShouldBeginEditing method, where following sequence of events are performed
UIKeyboardWillHideNotification is received corresponding to that field where the keyboard for the previous field is hidden.
the method textFieldShouldBeginEditing returns a YES and then
UIKeyboardWillShowNotification is received where the keyboard for the current field is displayed.
However, in OS 3.2 even though textFieldShouldBeginEditing returns a YES, UIKeyboardWillShowNotification for the current field is not received.
The logic works for OS < 3.2
Any ideas where I might be doing wrong?
Listed below a part of my code (with only two text fields in xib).
I need to perform a set of operations at keyboardWillShow and keyboardWillHide Look at the difference on running the code in OS 3.2 and OS < 3.2
Can anyone explain the difference in behaviour?
.h
#interface ExampleViewController : UIViewController
{
IBOutlet UITextField *numericTextField;
IBOutlet UITextField *alphaTextField;
UITextField *lastTextField;
int lastCursorPos;
int cursorPosition;
NSMutableArray *textFields;
}
#property (nonatomic, retain) UITextField *lastTextField;
#property (nonatomic, retain) NSMutableArray *textFields;
#end
.m
- (void)viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:self.view.window];
self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
self.textFields = [[NSMutableArray alloc] initWithCapacity:2];
[self.textFields insertObject:alphaTextField atIndex:0];
[self.textFields insertObject:numericTextField atIndex:1];
cursorPosition = 1;
[numericTextField becomeFirstResponder];
}
-(void)viewWillDisappear:(BOOL)animated
{
[self setEditing:NO animated:YES];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
int index;
for(UITextField *aField in self.textFields){
if (textField == aField){
index = [self.textFields indexOfObject:aField];
}
}
if(index>=0 ){
lastCursorPos = cursorPosition;
self.lastTextField = [self.textFields objectAtIndex:lastCursorPos-1];
cursorPosition = index +1;
}
[self.lastTextField resignFirstResponder];
return YES;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
- (void)keyboardWillShow:(NSNotification *)notif {
NSLog(#"Inside keyboardWillShow");
}
- (void)keyboardWillHide:(NSNotification *)notif {
NSLog(#"Inside keyboardWillHide");
}
I believe that as of iOS 3.2, UIKeyboardWillHideNotification and UIKeyboardWillShowNotification are no longer fired when switching between two text fields. Basically, the notifications only fire if the keyboard is actually shown or hidden, and since switching from one text field to another doesn't hide the keyboard, the event doesn't fire.
Prior to iOS 3.2 the events used to fire whenever you changed fields. The new way is arguably more correct, but it does make what you are trying to do a bit more challenging.
You might be better off implementing the delegate for the text fields, then you can check for the shouldBeginEditing/didEndEditing events, or alternatively, you could subclass UITextField and override the becomeFirstResponder/resignFirstResponder methods so that you can hook into them and implement your logic when the fields receive and lose focus.
I think you are trying to change the keyboard types when you are on a particular text field. Instead of tracing it the way your doing simply use the two methods,
- (void)textFieldDidBeginEditing:(UITextField *)textField;
- (BOOL)textFieldShouldReturn:(UITextField *)textField;
The first method is called whenever you touch a textfield for editing.
Here you can write you keyboard changing code
EG: If textfield is of type 1
set Keyboard Type to alphanumeric.
Else if textfield is of type 2
set Keyboard Type to numeric only.
Then the second method is called whenever you press the RETURN key on the onscreen keyboard.
Here you can write the [textfield resignFirstResponder] statement for any incoming textfield control.
Hope this helps.. :) cheers!
When the keyboard appears, the method is called by notificationCenter.
If it's not working set the object to nil.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:self.view.window];
Related
I read many post here about this topic, but I wasn't able to find an answer to my question, so, hope you won't be bored about another UIKeyboard post :-)
In my view controller's implementation I added self as an observer for the two notifications UIKeyboardWillShowNotification and UIKeyboardWillHideNotification, passing the selectors keyboardWillShow: and keyboardWillHide: to handle to notifications. As I touch a UITextField, the keyboardWillShow: method is called but when I press a "Done" button (which dismisses the keyboard) the keyboardWillHide: method is not called.
Really, I'd like to make my UITextField show a keyboard with the "hide button" on the bottom right of the keyboard, but I wasn't able to find the right keyboard type. Maybe I need to set the textfield retuntype to "...Done". In that way I saw that "return" key turns to "done".
So I set a toolbar to be my UITextField's inputAccessoryView, so now I can show a standard keyboard with a tool bar above with the "Done" button. As a user touches that button, I hide the keyboard with the resignFirstResponder method.
The strange thing is that when I call resignFirstResponder, the UIKeyboardWillHideNotification isn't posted; at least the keyboardWillHide: method is not called.
What do you suggest to me? I really wanted to display a keyboard with the small button with the down arrow to hide the keyboard, but also this solution could be right, but I'd like to resize the view and to do this I need to observer UIKeyboardWillHideNotification.
Thank you very much for help...
(ADDED:)
In viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:[[self view] window]];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:[[self view] window]];
I took these declarations from one of "yours" post :-) But the willShow works...
The action of the "Done" button that's in the UIToolbar that's assigned to be the inputAccessoryView of my text field is:
-(void)keyboardDone {
[msgTextField resignFirstResponder];
CLOSED:
OK! When a developer is stupid... it is stupid :-) :-)
This is my corrected willHide method:
-(void)keyboardWillHide:(NSNotification*)n {
NSDictionary* userInfo;
CGSize keyboardSize;
CGRect viewFrame;
/* This was the bad guy :) I forgot to delete it
* after I previously copied the willShow method that
* checks if keyboard is already shown (if so returns).
*
* if( keyboardIsShown )
* return;
*/
userInfo = [n userInfo];
keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
viewFrame = [[self scrollView] frame];
viewFrame.size.height += ( keyboardSize.height - TABBAR_HEIGHT );
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.5];
[[self scrollView] setFrame:viewFrame];
[UIView commitAnimations];
keyboardIsShown = NO;
NSLog(#"HIDE\n");
}
First of all I'd like to thank you all for this useless work in helping me. I'd like to give you some points, so I'll try to rise a "interest point" for each answer, but I need to choose the right one... hard part... :-)
Excuse me again... I really didn't see the if() statement...
If you read the documents for UIWindow it says that the notification object for these notifications is nil. You are passing self.view.window in as the object to the addObserver:selector:name:object: method. Try passing nil instead:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
It's important to note that when the user hides the software keyboard via the hide button, the hide methods aren't called. The show methods are called again, but the keyboard is nearly off screen except for the home row toolbar.
Check, if keyboardDone really gets called (i.e. with NSLog(#"%#", #"keyboard done called");). If its get called, but resignFirstResponder does not help dismissing the keyboard, then try this:
[self.view endEditing:YES];
Please also provide your keyboardWillHide: method.
To set the keyboard up so that it has a "Done" button, do this:
1) Setup your view controller so that it implements the UITextFieldDelegate. For Example:
#import <UIKit/UIKit.h>
#interface TX_ViewController : UIViewController <UITextFieldDelegate>
#property (nonatomic, retain) IBOutlet UITextField *textField;
#end
2) In your view controllers implementation file, use the following code to setup the keyboard:
- (void)viewDidLoad
{
[self.textField setDelegate:self];
[self.textField setReturnKeyType:UIReturnKeyDone];
[self.textField addTarget:self action:#selector(textFieldFinished:) forControlEvents:UIControlEventEditingDidEndOnExit];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
3) And if you wish to do something when the DONE button is pressed, simply add the following function to your view controller's implementation file:
- (IBAction)textFieldFinished:(id)sender
{
[sender resignFirstResponder];
}
Also, if you are using Interface builder to create your interfaces, don't forget to setup your IBOutlet reference for the TextField; otherwise, your class won't receive the messages from the XIB.
I set this up in a sample application just to see if it works and it did perform in the way you wish for your application to perform.
Swift $
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
func keyboardWillHide(notification: NSNotification){
print("keyboardWillHide")
}
I have a table view with a data source/delegate in another file. In addition, there is a search bar above the table view that belongs to the first file. In other to hide the keyboard when scrolling, I would need to call:
[self.searchBar resignFirstResponder]
But the
(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
method is in the delegate. So how would I hide the keyboard when scrolling in this case?
Thanks!
you could send a notification in scrollviewwillbegindragging. tableview delegate:
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
[[NSNotificationCenter defaultCenter] postNotificationName:#"resign" object:nil];
}
searchbar delegate:
-(void)viewDidLoad{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(goTo:) name:#"resign" object:nil];
}
-(void)goTo:(NSNotification*)notification {
[self.searchBar resignFirstResponder];
}
There are many ways to do,a couple of them are below.
option 1:
add below line after initializing your table object
[yourTableView setKeyboardDismissMode:UIScrollViewKeyboardDismissModeOnDrag];
or
option 2:
Get your tableview's superview(i'm expecting that as aViewcontrollerObj.view) and forcibly end its editing .
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
UIView *tableviewSuperView = yourTableView.superview;
[tableviewSuperView endEditing:true];
}
Hope that helps
Happy coding :)
I have a UITextField named textFieldInput and some button. Somehow I disable the input view so that if anyone tap in the texField no keyboard will show. I am adding text when a button is pressed programmatically. And I want to catch this changes. I want to call a function when the text of textField will change. How Can I do that?
I tried by adding following function
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)replacementStr {
// some my code
return YES;
}
But this does not work. this only calls when i tap on the textField.
I also tried by adding following in my viewDidLoad function
[textFieldInput addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
this also doesn't work.
How can I do this?
Thanks.
Register notification.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(textChanged:)
name:UITextFieldTextDidChangeNotification
object:YOUR_TEXT_FIELD];
shouldChangeCharactersInRange:
this will work only when you set its delegate with the controller which implements this method. one other way is:
add these line viewDidLod
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector (handle_TextFieldTextChanged:)
UITextFieldTextDidChangeNotification
object: textFieldInput];
and implement handle_TextFieldTextChanged:
- (void) handle_TextFieldTextChanged:(id)notification {
// write your logic here.
}
I am having trouble trying to figure out which UITextField is the current First Responder.
What I am trying to do is a set a boolean value if the user clicks in a particular UITextField. So to do that I need to be able to tell if this particular text field has become the first responder.
I know how to set the first responder but just not sure how to tell if a field has actually become the first responder.
[...] but just not sure how to tell if a field has actually become the
first responder.
UIView inherits the isFirstResponder method from UIResponder which tells you this.
The easiest way to find whatever the first responder is without checking individual controls/views and without multiple methods for all of the different types of possible first responders is to just make a category on UIView which adds a findFirstResponder method:
UIView+FirstResponder.h
#import <UIKit/UIKit.h>
#interface UIView (FirstResponder)
- (UIView *)findFirstResponder;
#end
UIView+FirstResponder.m
#import "UIView+FirstResponder.h"
#implementation UIView (FirstResponder)
- (UIView *)findFirstResponder
{
if ([self isFirstResponder])
return self;
for (UIView * subView in self.subviews)
{
UIView * fr = [subView findFirstResponder];
if (fr != nil)
return fr;
}
return nil;
}
#end
Why not using the UITextFieldDelegate and implement the textFieldDidBeginEditing: method? This will be called as soon as the textfield gains the focus.
UITextFieldDelegate Protocol Reference
if(![myTextField isFirstResponder])
{
// do stuff
}
I might do like this
Add property to ViewController
#property (nonatomic, strong) UITextField *firstRespondField;
Register TextField Notificaiton
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(textFieldTextDidBeginEditing:)
name:UITextFieldTextDidBeginEditingNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(textFieldTextDidEndEdition:)
name:UITextFieldTextDidEndEditingNotification
object:nil];
Dont forget remove it on Dealloc
[[NSNotificationCenter defaultCenter] removeObserver:self];
Then Implement 2 method
- (void)textFieldTextDidBeginEditing:(NSNotification *)aNotification {
self.firstRespondField = aNotification.object;
}
- (void)textFieldTextDidEndEdition:(NSNotification *)aNotification {
self.firstRespondField = nil;
}
Finally, I might get FirstResponder object by
self.firstRespondField
You can just call UIView.IsFirstResponder on the view you want to know if it's the first responder.
i need to add button done on keypad.
Apple does n't provide such felicity but some of application i found that done ,next,previous buttons.
like this.
how can i add these and how can i give click event to them.
can any one please help me.
1.Define the done button (= return key):
textField.returnKeyType = UIReturnKeyDone;
2.Add the action-listener:
[textField addTarget:self action:#selector(textFieldDoneEditing:) forControlEvents:UIControlEventEditingDidEndOnExit];
3.Define the action-event:
- (IBAction)textFieldDoneEditing:(id)sender {
[sender resignFirstResponder];
}
Have fun!
EDIT:
Here you can find detailed instructions how to add a Toolbar with Next & Previous above UITextField Keyboard:
http://www.randomsequence.com/articles/adding-a-toolbar-with-next-previous-above-uitextfield-keyboard-iphone/
EDIT2:
Now, I have a really great example for you: "This view extends UITextView adding on top of the keyboard associated with this UITextView a toolbar with a « Done » Button"
I check the code and it is a lot of easier than the first example:
http://blog.demay-fr.net/2009/07/cocoa-how-to-add-a-toolbar-with-button-on-top-of-a-uitextview-in-order-to-add-a-dismiss-button/
EDIT3:
Hmmm, no, I doesn't test to code. But I will test it now!
1.Problem: the right initialization. If I add the UITextView in IB, initWithCoder gets called:
- (id)init {
NSLog(#"init");
if (self = [super init]) {
//register a specific method on keyboard appearence
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
return self;
}
- (id)initWithCoder:(NSCoder *)decoder {
NSLog(#"initWithCoder");
if (self = [super initWithCoder:decoder]) {
//register a specific method on keyboard appearence
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
NSLog(#"initWithFrame");
if (self = [super initWithFrame:frame]) {
//register a specific method on keyboard appearence
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
return self;
}
2.Problem: There's no view with the the Prefix "UIKeyboard":
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
NSLog(#"keyboardWindow = %#", keyboardWindow);
for (UIView *keyboard in [keyboardWindow subviews]) {
NSLog(#"keyboard = %#", keyboard);
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES) {
// THERE'S NO VIEW 'UIKeyboard'!!!
}
}
}
The code doesn't work, I'm sorry... I don't know why there's no view "UIKeyboard"... Maybe the first example will help you at this point and you can build your own solution.