I need to keep track of which text field is the firstResponder for my custom keyboard to work. In the code below, I have grossly oversimplified my program, but here is the gist of the problem:
#implementation SimplePickerViewController
#synthesize pickerKeyboard;
#synthesize textView;
#synthesize textView2;
#synthesize firstResponder;
-(void)viewDidLoad{
pickerKeyboard = [[PickerKeyboardViewController alloc] initWithNibName:#"PickerKeyboard" bundle:nil];
pickerKeyboard.delegate = self;
[self.textView setInputView:pickerKeyboard.view];
[self.textView setDelegate:self];
[self.textView2 setInputView:pickerKeyboard.view];
[self.textView2 setDelegate:self];
}
-(void)hideKeyboard{
[self.firstResponder resignFirstResponder];
self.firstResponder = nil; //without this line, the code doesn't work.
}
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView{
self.firstResponder = textView;
[self.pickerKeyboard.picker reloadAllComponents];
return YES;
}
If I remove the line setting the firstResponder to nil, the code ceases to function properly, but I am not sure why. (Without that line, I can select the first textView to bring up the keyboard, but after that I can never bring the keyboard back. Any ideas? Thanks!
I'm not sure that I understand why firstResponder needs to be kept track of for a custom keyboard to work. I use a custom keyboard without knowing what the first responder is.
Do you use:
textView.inputView = pickerKeyboard
How about the following, called on the view to resign the first responder:
[self.view endEditing:NO];
I have had a similar problem and I have just figured out the issue. Somewhere in some part of Apple's first responder code, they are using a selector named firstResponder. When you created the property firstResponder you inadvertently overrode that selector. That will cause Apple's code to fail. This, in my humble opinion, is a bug in Apple's framework, and the firstResponder method isn't documented anywhere. Name your property myFirstResponder or anything else and everything should work just fine.
See Why does the keyboard not show when a view is popped from the navigation stack?
Related
Is it possible to dismiss the keyboard when you have MULTIPLE UITextFields ? If so how ?
As a side note, do I have to dismiss the keyboard for Each and Every field or can it be done globally ? Oh and it would be super cool if I don't have to touch the DONE button, I'd ideally like a solution that where the user touches anything BUT the field in question and the keyboard automagically disappears...
Oh and if you'd be so kind step by step instructions.
I should have added that I have a method already to resign the keyboard....
However, it only runs when my form is submitted! (see method below)
My question is how to the keyboard to hide/dismiss without having to jump thru so many damned hoops! You'd figure after 6 years, a mature operating system would have a way to GLOBALLY hide the keyboard....NOT!
Ok, enough whining....
- (void)hideKeyboard {
[self.dancePlace resignFirstResponder];
[self.danceGate resignFirstResponder];
[self.danceTerminal resignFirstResponder];
[self.danceText resignFirstResponder];
[self.danceDate resignFirstResponder];
[self.danceStyle resignFirstResponder];
[self.danceTimeOut resignFirstResponder];
}
And this is called when my button is submitted....
- (IBAction)addListingPressed:(id)sender {
// NSLog(#"BUTTON PRESSED");
[self hideKeyboard];
[self valuesAdded];
}
My question, assuming anyone can answer this...and I suspect not, is there a way to globally hide the keyboard if the following conditions are MET: 1.) the user taps OUT of any one of the existing fields, 2.) presses anywhere else on the screen. 3.) Is no more than a line or two in the existing viewcontroller.m file. 4.) I don't have to add a confusing button on the viewcontroller. (any time I have to add outlets, the damned thing is crashing on me...and then nastiness happens, and really...remember I am JUST a beginner, and its very confusing to read that I have to place this here and that there...oy. Simple folks, simple. I'm not looking for elegant solution, just so that it works.
I have a super class that all my view controllers inherit from. In that class I have this code.
MySuperViewController.h
#import <UIKit/UIKit.h>
#interface MySuperViewController : UIViewController
#property(strong, nonatomic) UITapGestureRecognizer *backgroundTapGestureRecognizer;
#end
MySuperViewController.m
- (void)viewDidLoad{
//add a tap gesture recognizer to capture all tap events
//this will include tap events when a user clicks off of a textfield
self.backgroundTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onBackgroundTap:)];
self.backgroundTapGestureRecognizer.numberOfTapsRequired = 1;
self.backgroundTapGestureRecognizer.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:self.backgroundTapGestureRecognizer];
}
- (void)onBackgroundTap:(id)sender{
//when the tap gesture recognizer gets an event, it calls endEditing on the view controller's view
//this should dismiss the keyboard
[[self view] endEditing:YES];
}
I have the UITapGestureRecognizer as a public property, so I can override it if I need to.
subclass
MyViewController.h
#import <UIKit/UIKit.h>
#import "MySuperViewController.h"
#interface MyViewController : MySuperViewController<UIGestureRecognizerDelegate>
#end
MyViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//You don't always want the keyboard to be dismissed, so you tie into the gesture recognizer's delegate method
//By doing this, you can stop the endEditing call from being made
[self.backgroundTapGestureRecognizer setDelegate:self];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
//touch.view is the view that recieved the touch
//if this view is another textfield or maybe a button, you can return NO and the endEditing call won't be made
if (touch.view == self.myViewThatShouldNotBeBlocked) {
return NO;
}
//if you want the gesture recognizer to accept the event, return yest
return YES;
}
I uploaded an example project to github.
https://github.com/JeffRegan/KeyboardBeGone
RDVKeyboardAvoiding is a scroll view with a tap gesture recognizer, designed for multiple textViews/textFields. It keeps track of the active view and removes a lot of boilerplate code.
tap anywhere outside the textField .. it will hide it..
[self.view endEditing:YES];
There are couple of other ways to do it.
[myEditField resignFirstResponder];
[myEditField endEditing];
[parentView endEditing];
If you dont wont to do so many things and simply want to dismiss keyboard than give iboutlet to each of your text filed to following method..
-(IBAction)hidekeyboard:(id)sender
{
[sender resignFirstResponder];
}
Yes, you only have to dismiss it for the one that is currently being edited.
In order to know which one is being edited, you can check the -(BOOL)isFirstResponder property, which will return YES if it is the first responder (the one being edited) or NO if it is not. Once you know which one is the first responder you can call -(void)resignFirstResponder on that one to get rid of the keyboard.
For example, if you have a method called -(void)aMethod that you want to dismiss the current view controller and you have an array of textViews called textArray, you could do a little loop such as:
-(void)aMethod {
for (UITextField *text in self.textArray) {
if ([text isFirstResponder]) [text resignFirstResponder];
return;
}
}
This way, you can have a variable number of textFields and it will still work.
If you only have one or two textFields and you do not want to create an Array object, you could do (assuming the fields are named text1 and text2:
-(void)aMethod {
if ([text1 isFirstResponder]) [text1 resignFirstResponder];
else if([text2 isFirstResponder]) [text2 resignFirstResponder];
}
Also, to make things easier for the future you could create a category method for UIView (which is what I do) to get the current first responder if it exists as a subview of that view:
#implementation UIView (GetFirstResponder)
- (UIView *)getFirstResponder {
if ([self isFirstResponder]) return self;
else {
for (UIView *subview in self.subviews) {
UIView *firstResponder = [subview getFirstResponder];
if (firstResponder) return firstResponder;
}
}
return nil;
}
You can put this method on the top of any file that you want to call it from, or create a separate file for it and import it.
Once you have this method, you can call:
- (void)aMethod {
UIView *view = [self.view getFirstResponder];
if (view) [view resignFirstResponder];
}
[superview endEditing:YES]; // superview can be the view controller's view property.
My ViewController implements UITextView delegate method textViewDidChangeSelection. Everything works just as expected when testing it. However, if the app is put in the background, and then becomes active again, the delegate method is not getting called when changing the selection in the TextView. Anyone else who had this problem?
My UITextView subclass does this:
self.inputView = [[UIView alloc] initWithFrame:CGRectZero];
The above is in order for the keyboard not to show up, but at the same time keeping the TextView enabled.
The subclass also does this:
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender{
{
if ( [UIMenuController sharedMenuController] )
{
[UIMenuController sharedMenuController].menuVisible = NO;
}
return NO;
}
This is in order not to show the copy paste pop up when clicking the UITextView. I think this method looks a bit weird, but I found it on SO a while ago, and it has done what it should.
The UITextView delegate method textViewDidChangeSelection: will fire again when the app returns from the background. So something else must be going on in your app.
Just to make sure I created a simple app with 2 UITextView controls, set their delegate to be the view controller and added this bit of code:
- (void) textViewDidChangeSelection:(UITextView *)textView
{
NSLog(#"Fire change selection.");
}
Works fine both before backgrounding the app and after coming back from backgrounding.
What solved the problem for me was to call
[myTextView reloadInputViews]
In the AppDelegate method:
-(void)applicationWillEnterForeground:
I don't know exactly why it works, so if someone has any good explanation, that would be very appreciated.
The keyboard that comes up with MFMailComposeViewController does not have any means to dismiss the keyboard once it comes up.
Does anyone have an idea of changing the keyboard. There are no UITextField exposed as you are actually in mail client at the time.
The mail composer isn't yours to modify, it is a system provided view controller which you are explicitly told not to modify in the docs:
Important: The mail composition interface itself is not customizable and must not be modified by your application. In addition, after presenting the interface, your application is not allowed to make further changes to the email content. The user may still edit the content using the interface, but programmatic changes are ignored. Thus, you must set the values of content fields before presenting the interface.
The cancel button is already there in the top left, what would "Done" do? Send the email? That's in the top right.
The MFMailComposeViewController doesn't have a "Done" button, because it assumes you will use that button as a return key (to make a new line).
If you really wanted to change the button to a "done" button, there is only one way I can think to do it:
Create a new MFMailComposeViewController.
Enumerate through [[mailComposer view] subviews].
Inspect each subview (and subviews of subviews, if required).
When you've found the UITextView that is the body, do the following:
// Get the UITextView from subview inspection
UITextView *textView;
// Declare this instance variable in your class #interface
id <UITextViewDelegate> originalTextViewDelegate;
// Get the original delegate
originalTextViewDelegate = [textView delegate];
// Override the delegate
[textView setDelegate:self];
// Set the return key type
[textView setReturnKeyType:UIReturnKeyDone];
Return YES on -textViewShouldEndEditing. Implement ALL UITextViewDelegate methods, and call originalTextViewDelegate (kind of like calling "super" on a subclass).
- (BOOL)textViewShouldEndEditing:(UITextView *)textView
{
[originalTextViewDelegate textViewShouldEndEditing:textView];
// Important: return YES, regardless of originalTextViewDelegate's response
return YES;
}
- (void)textViewDidChangeSelection:(UITextView *)textView
{
[originalTextViewDelegate textViewDidChangeSelection:textView];
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
return [originalTextViewDelegate textView:textView shouldChangeTextInRange:range replacementText:text];
}
// etc
That should work, but no guarantees. Hope that helps! :D
I have a simple view controller with a uisearchbar and a uitable.
My problem is that when search bar is tapped I see delegate function searchBarShouldBeginEditing being called but not searchBarTextDidBeginEditing(and because of that keyboard is not opened and search is not editable)
I tried to implement delegate function searchBarShouldBeginEditing returning YES, set searchbar as first responder, but no way I get searchBarTextDidBeginEditing called...
Any idea what could be happening??
Some code:
controller.h
#interface ViewController : UIViewController <UISearchBarDelegate>
{
UISearchBar * searchbar;
}
#property (nonatomic, retain) IBOutlet UISearchBar* searchbar;
#end
controller.m
#synthesize searchbar;
- (BOOL)respondsToSelector:(SEL)sel {
NSLog(#"Queried about %#", NSStringFromSelector(sel));
return [super respondsToSelector:sel];
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
NSLog(#"searchBarShouldBeginEditing -Are we getting here??");
return YES;
}
-(void) searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
NSLog(#"searchBarTextDidBeginEditing -Are we getting here??");
}
Of cousrse my class have plenty more code (that surely is affecting somehow searchbar) but if someone has got similar problems with searchbar it would be very apreciated its response ;)
I tryed to make simple application with only searchbar and obviously it works...
EDITING:
Testing a little bit I discovered that it is not something related with uisearchbar as I added a TextField getting same result (just textFieldShouldStartEditing delegate function being called)
Application has all view controllers inside a UITabBar cotroller, but I do not think this can cause all this mess...
EDITING2:
Really strange behaviour: Setting IBAction function to TouchDown event of a UITextfield works perfectly but setting IBAction function to EditingDidBegin never gets fired...
Why this event could not be called??
did you set the delegate property?
searchbar.delegate = self;
Maybe you somewhere call [searchbar resignFirstResponder]. It was the case in my similar problem.
I had this problem when I was converting from a standalone UISearchBar to a searchBar integrated into the UINavigationBar.
In converting my code, I was still allocating the UISearchBar and setting the delegate for that. What I should have been doing was configuring the searchBar that comes as part of of the UISearchController, and setting the delegate of that,
self.searchController.searchBar.delegate = self;
Once I did that, my delegate methods started firing!
I've just started with xcode and objective-c and did some very basic apps, but what i'm having problem with is very basic this. the keyboard return button not hiding the keyboard.
I've searched the internet for the solution and all they say is to connect delegate to the file's owner and add the function and it should work, i did that and nothing is working.
I have an ok button and it is working and also clicking on any free space on the screen is working, just the return button....
I am using the simulator, not testing on iphone yet. (xcode 3.2.5 64 bit with the 4.2 simulator).
This is the line of code that should connect the delegate to every textFiled.
1. i've tried already to return both YES and NO, didn't work.
2. i've tried both a specific object name for the textField and this general way, didn't work.
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
In the: basic view controller connection -> connections -> outlets, i have the: delegate -- File's Owner. and in the file's owner in referencing outlets there is: delegate - Round style text.....
EDIT - i forgot to mention before, i've check and the method isn't being called!!!
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
NSLog(#"Working!!!");
[textField resignFirstResponder];
return YES;
}
what should i do to make it happen? that is why people say to connect the delegate, but in my case it is connected and not triggering the function...i know it is kind of dumb question but for a nobie like me the solution is not obvious...
OK, another Edit - with all my code: just can't understand what to do....
This is: basicViewController.h:
#import <UIKit/UIKit.h>
#interface basicViewController : <#superclass#> <UITextFieldDelegate>
#interface basicViewController : UIViewController <UITextFieldDelegate> {
//every object that we want to interact with (like text field or lable) is call an outlet!!!!
//here we define the outlets for our program
IBOutlet UITextField *txtName;
IBOutlet UILabel *lblMessage;
}
//here are the getters and setter for our outlets
#property (nonatomic, retain) IBOutlet UITextField *txtName;
#property (nonatomic, retain) IBOutlet UILabel *lblMessage;
//method decleration for the OK button action
- (IBAction) doSomething;
//method for hiding the keyboard when clicking on empty area in the app
//we will put an invisible button on all area and clicking on it will make keyboard disapear
- (IBAction) makeKeyboardGoAway;
#end
This is basicViewController.m:
#import "basicViewController.h"
#implementation basicViewController
//synthesizeing the objects that we made' this will create the getter and setters automaticly
#synthesize txtName;
#synthesize lblMessage;
- (IBAction) doSomething{
// makeing keyboard disapear when pressing ok button (doing that form the text field)
//when pressing the OK button, the keyboard will disapear and when clicking in the text field it will show again
[txtName resignFirstResponder];
NSString *msg = [[NSString alloc] initWithFormat:#"Hello, %#",txtName.text];
//the objective-c way for setting the test in the text field
[lblMessage setText:msg];
//the regular object oriented way
//lblMessage.text = msg;
[msg release];
}
- (IBAction) makeKeyboardGoAway{
[txtName resignFirstResponder];
}
//when clicking the return button in the keybaord
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
NSLog(#"Working!!!");
[textField resignFirstResponder];
return YES;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
Maybe now i am more clear, sorry i didn't do it before.
Any one has an idea what am i doing wrong? it should be pretty strait forward.....
EDIT - Adding an image of all the elements, i hope that will help to help me :-)
10x a lot for every one that is trying to help....i really like this framework, it is so great after c++ and java, python and many other...and i am working with a book, but it is for ios 3.1, maybe that is the problem.....
Firstly you should check if textFieldShouldReturn: is actually being called by adding an NSLog statement or breakpoint at the beginning of the method.
Once that's out of the way, try an manually declare that your view controller conforms to <UITextFieldDelegate> protocol in your interface file:
#interface YourClass : ... <UITextFieldDelegate>
Also declare a property & outlet for your UITextField, make the appropriate connections in IB and manually declare self as the UITextField delegate with:
self.yourUITextFieldObject.delegate = self;
Once that's done see if your method above is now being called and make sure you return YES.
Just write one line in the
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
}
before return YES;
the final version will be as given below:
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
-(void)textFieldDidEndEditing:(UITextField *)textField{
NSLog(#"%#",textField.text);
}
You need to assign the delegate of the textfields to your file owner. The textfields are sending the message, but doesn't have a delegate to respond to it.
Use the interface builder to do that.
You have to implement this method..
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
Like Rog said, don't forget to register the textfield to the delegate, you can do this manually as he said but in Storyboard you can just control drag from all of your textfields to the view controller and register the delegate (choose delegate). Only the textfields that are registered can make use of all those methods.
So this line is important:
self.yourUITextFieldObject.delegate = self;
Or even more easy these days is to just use the storyboard:
textfield is in a subview? in this case, make sure textfield have as delegate the FileOwner.
put a log at the
- (IBAction) makeKeyboardGoAway
function. I think its this method everytime anything is tapped on the screen. In that case, you will need to send the touch event to the text field. Not sure how this is done but that should do it.
Else try removing the which takes care of tap(click) all over the view and try to do what you are doing.
Most likely the problem is that your actual view controller in the running application is not a "basicViewController" but a UIViewController that does not implement the UITextFieldDelegate-protocol.
What you've done in the interface builder by selecting your class "basicViewController" as the FilesOwner is just declaring the FilesOwner-object in your running application to be of type basicViewController; the actual object is not instantiated by this declaration and in your case it is not in the xib / nib.
Some other part of your code actually instantiates a view controller object and loads the xib / nib file. At that place, I guess your code is instantiating a UIViewController (typically by auto-generated code) and not an instance of your basicViewController; you simply have to change the class there.
Furthermore, this error often happens when using a UINavigationController or UITabBarController in the Interface Builder that is (should be) configured to instantiate and load other custom views. If you use such a higher-level controller, double-check that it is actually configured to use your basicViewController, not UIViewController when loading your view from the xib / nib.
Hope, that solves the issue!
Can you try this..
#interface ClassName : SuperClass < UITextFieldDelegate >
Use like this...
textfield.delegate=self;
and use the UITextFieldDelegate in .h class
You can always dismiss the keyboard when you don’t even know which view the text field is in by using:
Objective-C:
[[UIApplication sharedApplication] sendAction:#selector(resignFirstResponder)
to:nil
from:nil
forEvent:nil];
Swift:
UIApplication.sharedApplication().sendAction("resignFirstResponder",
to:nil,
from:nil,
forEvent:nil)