I have a UISearchBar that, even though it is the first responder, the keyboard is not shown. I can start typing in the search bar using the laptop's keyboard, and I can see what I type inside the search bar, but the keyboard in the Simulator and on the actual iPad does not appear. It worked fine under iOS 3.2, but stopped working after updating to iOS 4.2 this morning.
Below is the relevant code:
// Text Field that when touched will fire a search view that contains the search bar
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[textField resignFirstResponder];
UIViewController *detailViewController = nil;
ImplementedSearchViewController *searchController =
[[ImplementedSearchViewController alloc] initWithNibName:#"ImplementedSearchView" bundle:nil];
...
detailViewController = searchController;
MyAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
UINavigationController *nav = (UINavigationController *)
[delegate.splitViewController.viewControllers objectAtIndex: 0];
NSArray *viewControllers = [NSArray arrayWithObjects:nav,
detailViewController, nil];
self.splitViewController.viewControllers = viewControllers;
HomeViewController *hHomeController = [nav.viewControllers objectAtIndex:0];
// Dismiss the popover if it's present.
if (homeController.popoverController != nil) {
[homeController.popoverController dismissPopoverAnimated:YES];
}
// Configure the new view controller's popover button
(after the view has been displayed and its toolbar/navigation bar has been created).
if (homeController.rootPopoverButtonItem != nil) {
[detailViewController
showRootPopoverButtonItem:homeController.rootPopoverButtonItem];
}
[detailViewController release];
}
// Inside the viewDidLoad of the search view
- (void)viewDidLoad {
self.table.frame = CGRectMake(table.frame.origin.x, table.frame.origin.y, table.frame.size.width, 680);
self.table.backgroundColor = [UIColor colorWithRed:239/255.0 green:244/255.0 blue:255/255.0 alpha:1.0];
// searchBar is a UISearchBar
[self.searchBar becomeFirstResponder];
}
The ui search bar in viewDidLoad is not nil.
Any thoughts on this?
Thanks,
Mihai
I was showing searchbar on textFieldDidBeginEditing:(UITextField *)textField delegate method.
Keyboard was not showing. So for that first resign textField as firstResponder.
i.e.
[textField resignFirstResponder];
Then call method with delay
[self performSelector:#selector(callSearchBar) withObject:NULL afterDelay:0.2];
Where
-(void)callSearchBar{
[self.searchDisplayController setActive: YES animated: YES];
self.searchDisplayController.searchBar.hidden = NO;
[self.searchDisplayController.searchBar becomeFirstResponder];
}
It works
I am using the same ui search bar in different places. It works in all but two. I believe that the problem has to do with the text field not resigning as first responder (although I called resignFirstResponder on that text field). In one of the places that it works, I'm also using a text field to trigger the search bar, but I'm using a selector instead of a text field delegate method (such as textFieldDidBeginEditing). If I switch from using a selector to using the delegate method, it stops working and I get the same issue (keyboard not appearing). I thought that, for the two cases where it doesn't work, the solution would be to switch from using the delegate method to using a selector, but it didn't. What I ended up doing was switching from using a text field to using a button. In a way, it doesn't make any sense using a text field if you are not going to write anything in it (I was only using it to trigger the search bar).
I can verify, that resigning the first responder in favor of the searchbar solves the problem on an iPad under iOS 4.3. In my case I had an UIViewController responding to UIEventSubtypeMotionShake. You had to explicitely call resignFirstResponder before(!)
removing thie UIViewController from the view hierarchy to make it work.
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake){
...
}
}
...
[someViewController becomeFirstResponder];
...
[someViewController resignFirstResponder];
[[someViewController view ] removeFromSuperview];
... (in my case I added a hierarchy including an UITabBarController, with a Tab including a UINavigationController covering the Searchcontroller to the window instead)
[searchViewController. searchbar becomeFirstResponder];
No clue, why this was not necessary on iPhone.
[self.searchDisplayController setActive: YES animated: YES];
self.searchDisplayController.searchBar.hidden = NO;
[self.searchDisplayController.searchBar becomeFirstResponder];
This answer from Mann(https://stackoverflow.com/users/871079/mann) worked for me. Thank you very much.
Related
My view controller structure on story board.
Main View -> scroll view -> view -> 3 text field(On main view add one scroll view, again add one view and than add 3 text field).
On 1st textfield(Date), open date picker.
on 2nd textfield(city), open new view controller for city list and after selecting city it will open new view controller for work area.After selecting work area it will come back to main view controller and selected city and work area is display in second text(city) field.
on 3rd textfield (Customer), open normal keyboard.
It is working fine but the problem is if I click on customer textfield, it will open keyboard at same time I click on city textfield than it will open city list View Controller but keyboard is not dismiss. keyboard is also show on city list view controller.
I have already try below thinks.
I am already trying with [self.view endEditing:YES] and resignFirstResponder. But not getting any successful result.
I have assign the tag to textfield And also set delegate in viewDidLoad() Method.
I have also assign the delegate from storyboard.
self.cityOrAreaTXTFld.delegate = self;
self.selectCustTXTFld.delegate = self;
self.dateTXTFld.tag = 1;
self.cityOrAreaTXTFld.tag = 2;
self.selectCustTXTFld.tag = 3;
My textFieldDidBeginEditing()Method
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if(textField.tag==1){
NSLog(#"Code to open date picker");
}
else if (textField.tag==2){
[self.view endEditing:YES];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *CityPEVC = [storyboard instantiateViewControllerWithIdentifier:#"CityListViewController"];
[self.navigationController pushViewController:CityPEVC animated:YES];
return;
}
else if(textField.tag==3)
{
[_dateTXTFld resignFirstResponder];
[_cityOrAreaTXTFld resignFirstResponder];
}
}
I have one solution for this
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if(textField.tag == 2)
{
[_dateTXTFld resignFirstResponder];
[_selectCustTXTFld resignFirstResponder];
return YES;
}
else
return YES;
}
In this solution, If key board is not open than not an issue but if any keyboard is open on main view controller and First time click on city textfield it will dismiss the keyboard(not open city list VC) and second time click on city textfield that time it will open city list view controller.
Is there any solution, if any other textfield keyboard is open on main view controller, and I click on city list textfield. Than how to dismiss that keyboard and same time open city list view controller?
I guess it would make sense to use it inside viewWillDisappear: in order to hide the keyboard before the controller is dismissed
[self.view endEditing:YES];
Apply this method on TouchesBegan function
sample code is below:
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];
}
When you touch any where in screen it will dismiss keyboard.
viewController.h
#interface yourViewcontroller : UIViewController
<
UITextFieldDelegate
>
viewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
yourTextField.delegate=self;
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self.view endEditing:YES];//dismiss all text field
return YES;
}
I've got a HomeViewController that has different modal segues to several other UIViewControllers. If I try to show the keyboard on a UITextField within the HomeView, everything works fine. However, if I try to show the keyboard on a UITextField (using becomeFirstResponder) after returning from any of the modal View Controllers, the keyboard never shows.
Here's some sample code from one of the setups I've tried:
In HomeViewController:
- (void)viewDidAppear:(BOOL)animated
{
static BOOL firstTimeComplete = false;
if (!firstTimeComplete) {
firstTimeComplete = true;
} else {
UITextField *textField = [[UITextField alloc] init];
[self.view addSubview:textField];
[textField performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:3]
}
}
In ModalViewController:
- (IBAction)done:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
Where done: is linked to the "Done" button via a touch up inside event.
A few things I've tried:
Converting the modal segues to push segues fixes the issue, but I don't want a Nav bar in any of the child views
I've tried disabling and enabling animations when dismissing the
modal view controller (using dismissViewControllerAnimated:)
Using unwind segues in the storyboard rather than doing it programmatically
Anyone have an idea of what may be going on?
After deleting tons of code, I finally found out that a custom NavigationController was being used and this was the root cause:
#implementation MSLNavigationController
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotate
{
return NO;
}
#end
The app doesn't need this code, so I've nuked the file. (But an explanation as to why this would be hiding the keyboard would be awesome :))
You did not call [super viewDidAppear:animated]
In place like that i have workaround that works pretty well
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^
{
if (self.textView.text.isNotEmpty)
{
[self.textView becomeFirstResponder];
}
});
}
I have been struggling with this problem for some time, so I'll post here what I found out.
I was calling textField.becomeFirstResponder() in viewWillAppear but on iOS 7, after the modal was dismissed, the keyboard would not show again, even when you would tap on the textField.
For me calling textField.resignFirstResponder() when the modal is presented, solved the issue. It seems like the input field was already marked as first responder and then would not react to the new calls.
In an app that's supposed to run on iOS 6 and iOS 7, the cancel button of the search bar embedded in the navigation bar is not shown anymore if the app is run on iOS 7. On iOS 6, it works.
The search bar is in the title view of the navigation bar and the cancel button should be shown if the search bar becomes the first responder:
iOS 7
iOS 6
In an isolated test case, the code is very simple:
#interface MyViewController : UITableViewController<UISearchBarDelegate>
#property (nonatomic) IBOutlet UISearchBar* searchBar;
#end
#implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.titleView = self.searchBar;
}
- (void) searchBarTextDidBeginEditing: (UISearchBar*) searchBar {
[searchBar setShowsCancelButton: YES animated: YES];
}
#end
Is this a deliberate change in iOS 7 that I missed in the documentation? If yes, what is supposed to be the alternative?
If not, have I made a mistake in my code?
It looks like you're doing everything correctly, but apparently Apple has changed around some things in iOS 7. According to this SO question in iOS 7 the cancel button doesn't appear on a UISearchBar embedded in a UINavigationBar.
According to the developer documentation, the showsCancelButton property may have a slightly different effect than the setShowsCancelButton:Animated method. Try doing this:
searchBar.showsCancelButton = YES;
[searchBar setShowsCancelButton:YES animated:YES];
I'm not sure if that will have any impact. You could also try placing the code in a different delegate method:
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar; // return NO to not become first responder
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar; // called when text starts editing
You may also want to checkout the iOS 7 changelog. It looks like Apple changed the behavior or a UISearchDisplayController / UISearchBar when added to a UINavigationBar. Take a look at the last bullet point under the UIKit section (although it isn't clear exactly what was changed).
You may also want to try using a UISerachDisplayController. What might be even easier is to embed the UISearchBar in the header of a UITableView.
I've solved this problem simple, just by adding rightBarButtonItem :)
self.navigationItem.titleView = self.searchBar;
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"Cancel", nil) style:UIBarButtonItemStylePlain target:self action:#selector(didClickCancelButton:)] autorelease];
But sure you have to check if current iOS version is >= 7.0, otherwise you will get two "cancel" buttons..
BTW This method allows you to have "cancel" button which always enabled
iOS 7 is different with iOS 6 in navigation bar, so if you want to show UISearch bar in navigation bar,you can try this:
put your UISearchbar on a UIView like this[self.searchView addSubview self.searchBar], and set the navigationbar's titleView to your searchView like thisself.navagitioncontroller.navigationItem.titleView = self.searchView
Hope it works for you
If you are using your UISearchBar with an UISearchDisplayController, you can simply set the cancel button to show, in the "searchDisplayControllerWillBeginSearch" delegate method, like so: (iOS 7 tested)
-(void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller{
controller.searchBar.showsCancelButton = YES;
}
There does seem to be a change between iOS6 and iOS7 in that changes to the UI from xxxDidYYY methods sometimes don't work, and you have to do it in the xxxWillYYY method or in some code executed from the main event loop (e.g. in a block or after a short delay).
In your case, try this:
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
searchBar.showsCancelButton = YES;
return YES;
}
In my opinion this is a bug. Heres my workaround. It's not perfect but it works both on iOS 6&7. On iOS7 the searchbar textfield slides over the cancel button while it's fading out and on iOS6 the textfield width expansion isn't animated.
#interface FTViewController ()
#property(nonatomic, strong) UISearchBar *searchBar;
#end
#implementation FTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.searchBar = [[UISearchBar alloc] init];
self.searchBar.delegate = self;
if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_6_1) {
// iOS 6.1 and older (only tested on 6.1)
[self.searchBar sizeToFit];
self.searchBar.backgroundImage = nil;
}
self.navigationItem.titleView = self.searchBar;
}
-(void)cancelBarButtonItemClicked:(id)sender
{
[self searchBarCancelButtonClicked:self.searchBar];
}
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
[self.navigationItem setRightBarButtonItem:nil animated:YES];
}
-(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
UIBarButtonItem *cancelBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(cancelBarButtonItemClicked:)];
[self.navigationItem setRightBarButtonItem:cancelBtn animated:YES];
return YES;
}
#end
There are two options:
Add a search bar like a subview to uiviewcontroller.view and hide a navigation bar if needs
Add a cancel button to uiviewcontroller.navigationItem.rightBarButtonItem
my preference is the second one, but it looks more native with the first one.
This is indeed a bug that is fixed as of 7.1.
My keyboard appears with a textView, I want to hide it when the user push on a back button on a navigation bar.
I have tried this:
-(void)viewWillDisappear:(BOOL)animated{
[myTextView resignFirstResponder];
}
and this:
-(void)viewDidDisappear:(BOOL)animated{
[myTextView resignFirstResponder];
}
But it doesn't work, how can I do this?
edit:
I found the solution here:
iPad keyboard will not dismiss if modal ViewController presentation style is UIModalPresentationFormSheet
Put this into the buttonPress method -
[self.view.window endEditing:YES];
Edit - this also lets you get the contents of the text being edited when the "back" button is pressed
Combining the above answers and checking for back button will be done by this
- (void)viewWillDisappear:(BOOL)animated{
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
// back button was pressed. We know this is true because self is no longer
// in the navigation stack.
[self.view.window endEditing:YES];
}
[super viewWillDisappear:animated];
}
Note:
See accepted answer (not top voted one) for solution as of iOS 4.3.
This question is about a behavior discovered in the iPad keyboard, where it refuses to be dismissed if shown in a modal dialog with a navigation controller.
Basically, if I present the navigation controller with the following line as below:
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
The keyboard refuses to be dismissed. If I comment out this line, the keyboard goes away fine.
...
I've got two textFields, username and password; username has a Next button and password has a Done button. The keyboard won't go away if I present this in a modal navigation controller.
WORKS
broken *b = [[broken alloc] initWithNibName:#"broken" bundle:nil];
[self.view addSubview:b.view];
DOES NOT WORK
broken *b = [[broken alloc] initWithNibName:#"broken" bundle:nil];
UINavigationController *navigationController =
[[UINavigationController alloc]
initWithRootViewController:b];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
navigationController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];
If I remove the navigation controller part and present 'b' as a modal view controller by itself, it works. Is the navigation controller the problem?
WORKS
broken *b = [[broken alloc] initWithNibName:#"broken" bundle:nil];
b.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:b animated:YES];
[b release];
WORKS
broken *b = [[broken alloc] initWithNibName:#"broken" bundle:nil];
UINavigationController *navigationController =
[[UINavigationController alloc]
initWithRootViewController:b];
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];
This has been classified as "works as intended" by Apple engineers. I filed a bug for this a while back. Their reasoning is that the user is often going to be entering data in a modal form so they are trying to be "helpful" and keep the keyboard visible where ordinarily various transitions within the modal view can cause the keyboard to show/hide repeatedly.
edit: here is the response of an Apple engineer on the developer forums:
Was your view by any chance presented with the UIModalPresentationFormSheet style? To avoid frequent in-and-out animations, the keyboard will sometimes remain on-screen even when there is no first responder. This is not a bug.
This is giving a lot of people problems (myself included) but at the moment there doesn't seem to be a way to work around it.
UPDATE:
In iOS 4.3 and later, you can now implement `-disablesAutomaticKeyboardDismissal' on your view controller to return NO:
- (BOOL)disablesAutomaticKeyboardDismissal {
return NO;
}
This fixes the issue.
Be careful if you are displaying the modal with a UINavigationController. You then have to set the disablesAutomaticKeyboardDismissal on the navigation controller and not on the view controller. You can easily do this with categories.
File: UINavigationController+KeyboardDismiss.h
#import <Foundation/Foundation.h>
#interface UINavigationController (KeyboardDismiss)
- (BOOL)disablesAutomaticKeyboardDismissal;
#end
File: UINavigationController+KeyboardDismiss.m
#import "UINavigationController+KeyboardDismiss.h"
#implementation UINavigationController(KeyboardDismiss)
- (BOOL)disablesAutomaticKeyboardDismissal
{
return NO;
}
#end
Do not forget to import the category in the file where you use the
UINavigationController.
In the view controller that is presented modally, just override disablesAutomaticKeyboardDismissal to return NO:
- (BOOL)disablesAutomaticKeyboardDismissal {
return NO;
}
I solved this by using the UIModalPresentationPageSheet presentation style and resizing it immediately after I present it. Like so:
viewController.modalPresentationStyle = UIModalPresentationPageSheet;
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:viewController animated:YES];
viewController.view.superview.autoresizingMask =
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleBottomMargin;
viewController.view.superview.frame = CGRectMake(
viewController.view.superview.frame.origin.x,
viewController.view.superview.frame.origin.y,
540.0f,
529.0f
);
viewController.view.superview.center = self.view.center;
[viewController release];
If you toggle a different modal display you can get the keyboard to disappear. It's not pretty and it doesn't animate down, but you can get it to go away.
It'd be great if there was a fix, but for now this works. You can wedge it in a category on UIViewController and call it when you want the keyboard gone:
#interface _TempUIVC : UIViewController
#end
#implementation _TempUIVC
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
#end
#implementation UIViewController (Helpers)
- (void)_dismissModalViewController {
[self dismissModalViewControllerAnimated:NO];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
[self release];
}
- (void)forceKeyboardDismissUsingModalToggle:(BOOL)animated {
[self retain];
_TempUIVC *tuivc = [[_TempUIVC alloc] init];
tuivc.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:tuivc animated:animated];
if (animated) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_dismissModalViewController) name:UIKeyboardDidHideNotification object:nil];
} else
[self _dismissModalViewController];
[tuivc release];
}
#end
Be careful with this though as you viewDidAppear / viewDidDisappear and all those methods get called. Like I said, it's not pretty, but does work.
-Adam
You could also work around this in a universal app by simply checking the idiom and if it's an iPad, don't pop up the keyboard automatically at all and let the user tap whatever they want to edit.
May not be the nicest solution but it's very straightforward and doesn't need any fancy hacks that will break with the next major iOS release :)
Put this code in your viewWillDisappear: method of current controller is another way to fix this:
Class UIKeyboardImpl = NSClassFromString(#"UIKeyboardImpl");
id activeInstance = [UIKeyboardImpl performSelector:#selector(activeInstance)];
[activeInstance performSelector:#selector(dismissKeyboard)];
I found that disablesAutomaticKeyboardDismissal and adding a disablesAutomaticKeyboardDismissal function didn't work for my UITextField in a modal dialog.
The onscreen keyboard just wouldn't go away.
My solution was to disable all text-input controls in my dialog, then re-enable the relevant ones a fraction of a second later.
It seems as though when iOS sees that none of the UITextField controls are enabled, then it does get rid of the keyboard.
I'm sure you have looked at this, but you are sure that your controller class is properly hooked up as the UITextField delegate, right?
maybe don't return NO, but YES. So it can go away.
And you have a textFieldShouldEndEditing returning YES as well?
And why are you firing [nextResponder becomeFirstResponder]?! sorry i see now
I also have a number of UITextViews
which all have their "editable"
property set to FALSE.
May we assume none of them, by any chance, has a tag value of secondField.tag+1? If so, you're telling them to become first responder, instead of resigning the first responder. Maybe put some NSLog() in that if structure.
For those having trouble with UINavigationController, see my answer to a similar question here:
https://stackoverflow.com/a/10507689/321785
Edit:
I consider this an improvement to Miha Hribar's solution (since the decision is taking place where it should), and as opposed to Pascal's comment regarding a category on UIViewController
may be not a perfect solution ,but works
[self.view endEditing:YES];
from wherever your button or gesture is implemented to present modal
Swift 4.1:
extension UINavigationController {
override open var disablesAutomaticKeyboardDismissal: Bool {
return false
}
}