I have a nav controller with a toolbar. I made the toolbar also appear on top of the keyboard when the keyboard appears. When I dismiss the keyboard, the toolbar disappears, leaving a black rectangle at the bottom of the screen, just where the toolbar should be without the keyboard.
Here's how I init the toolbar:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setToolbarHidden:NO];
// this makes sure the toolbar appears on top of the keyboard
// instead of going below it.
// _nameText is a UITextField
_nameText.inputAccessoryView = self.navigationController.toolbar;
}
This is how I hide the keyboard:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
[self.navigationController setToolbarHidden:NO]; // this doesn't help
return NO;
}
I tried also doing [self.view setNeedsLayout], but that didn't work.
EDIT: I suspect this may have to do with the fact that I assign the toolbar to be the input accessory view of my text field. I think that the text field hides its accessory view when the keyboard goes away. I still don't know how to override that behavior though.
EDIT 2: I discovered that self.navigationController.toolbar.superview is nil after the keyboard is gone.
OK, so while I couldn't solve the problem head-on, I found an acceptable workaround.
Create a .xib for your toolbar
Load the toolbar from (1) into an object
assign that object to the inputAccessoryView property of your text field
set up the target and the actions for the buttons in this toolbar, so you can respond to clicks
You are now all set. Your original toolbar (which you presumably have created in the Interface Builder) is only visible when the keyboard is hidden. When the keyboard is visible, the original toolbar cannot be seen, but your other one (created with the steps described above) now appears above the keyboard. Bingo!
If anyone has a more elegant solution to this problem, I'd be happy to hear about it :)
#BlackRider, I ran into the same exact issue as you. It is quite annoying.
I didn't want to set up 2 different toolbars as a workaround, as I didn't want to handle the state of the toolbar buttons in 2 different places.
I've resorted to using the approach discussed here in the answer that uses notifications: iPhone: How to fix inputAccessoryView to View?
It's working ok - my gut reaction is that I'll run into issues when trying on various device sizes / orientations.
Related
I know that the view controller must be firstResponder in order for the inputAccessory to stay at the bottom. I am using a custom inputView / keyboard. I can manually dismiss it with a done button by removing the inputView but not resigning first responder. However when I enable the interactive drag to dismiss on my scrollview, the code automatically resigns first responder. So how can I use the interactive drag to dismiss and yet keep my viewcontroller as first responder? Anyone done this before? I thought maybe it is not possible and that I may need to make my own interactive drag to dismiss using a gesture recognizer.
More info:
I have a button that swaps between standard keyboard and my custom one. I have seen dismissing these cause 2 keyboard did dismiss notifications. I thought I could become firstResponder in the keyboardDidHide method but this didn't work well since I couldn't tell the difference between when I manually dismissed the keyboard and when the interactive drag does it. This matters because I don't need to reload the input view or become first responder when I manually dismiss because I took care of it already.
Any suggestions would be amazing. I am trying to use inputView and inputAccessoryView on the UIViewController level.
Well after a day of pulling my hair, I have an answer.
Using the canResignFirstResponder of my viewcontroller did the trick. In viewWillAppear I set a BOOL responderOverride = YES;
In viewWillDisappear I call
responderOverride = NO;
[self resignFirstResponder];
When the interactive drag on the scrollview tries to resignFirstResponder, canResignFirstResponder returns no which prevents my viewcontroller from resigning and keeps my input accessory retained and sitting at the bottom of the screen.
There is a lot of other code with reloading input views but since the real question was how to force a controller to stay first responder so we don't lose our input accessory view, then this solution works.
override var canBecomeFirstResponder : Bool {
get {
retrun true
}
}
This works for me
In my iOS project, I have a form which contains various text fields. Some text fields are edited by keyboard and some by picker view which is placed on the popover.
When I go on filling text fields, without dismissing it and then if I click on popover text field keyboard remains open.
It appears as both keyboard and popover present on screen at the same time, which I don't want.
I am able to get whether the keyboard is opened or not by setting a flag in keyboard notification methods and also the last text field that was edited through text filed delegates. And have tried
[self endEditing: YES]; (as it is in a table cell)
[lastEditedTextField resignFirstResponder];
Even try to pass keyboard dismiss the notification by my self (without knowing whether it is possible or not)
[[NSNotificationCenter defaultCenter] postNotificationName:UIKeyboardWillHideNotification object:nil];
but nothing is working.
How can I dismiss keyboard (if already open) whenever popover appears?
You can call:
[self.view endEditing:YES];
But, a better solution is likely to present the picker using the UIResponder
inputView so it automatically replaces the keyboard and you don't need to mediate between 2 different things (and the user doesn't switch between different parts of the screen potentially).
Try to implement textFieldShouldBeginEditing: and inside it check which text field is this. If it is one of the fields that should display a popover, first call [self.view endEditing:YES] to hide the keyboard, then present the popover and return NO. This way the text field won't take first responder status and the keyboard will not appear again. And if it is one of the "normal" text fields, just return YES.
I'm trying to get a search bar and it's scope in the navigation bar, as the way the view first appears. If you simply drag a UISearchBar onto you table view controller in interface builder, it's placed in your table like a header cell. Then, when you tap it, it animates into the formation I'm after below. The problem is I want it to start out this way without any tapping, with a back button on the left and no cancel button on the right:
So, to give the search bar immediate focus without tapping, I tried adding [_searchBar becomeFirstResponder]; in viewDidLoad which doesn't work. Next I tried:
self.searchDisplayController.displaysSearchBarInNavigationBar = YES;
The search bar will indeed display in the navigation bar but the scope bar is gone, (WHY APPLE WHY) and there is an awkward gap.
I've also tried subclassing UINavigationBar and making it taller. It's easy to change it's size but the contents align at the bottom of the bar and overlap anything you try to add to it.
So to re-iterate, I need the search bar to display in the navigation bar with a scope control when the view first appears, without any tapping by the user. I should also specify that this is on a UITableViewController (because the page has a UIRefreshConrol), so simply dropping a toolbar in above the table view isn't an option. Thanks.
tl;dr: Don't.
You should know that adding a UISearchBar to the headerView of a UITableView invokes some custom code within UIKit that facilitates hiding the scope bar on start. While it used to be easier to show the scope bar all the time in iOS 6 and older, iOS 7 has changed this.
Your first approach, to becomeFirstResponder in viewDidLoad was a good idea, but this method is called after the view has been loaded into memory (such as out of a NIB). The view has not yet been added to the view hierarchy, so it can't become the first responder. viewDidAppear: is called right after the view is loaded into the view hierarchy, and a becomeFirstResponder does in fact allow the UISearchBar to receive focus.
The scope bar itself is a hidden (by default) subview of UISearchBar. You technically could just cycle through subviews and set it to not be hidden:
- (void)viewDidLoad
{
[super viewDidLoad];
[self recurseSubviewsForView:self.searchDisplayController.searchBar];
}
- (void)recurseSubviewsForView:(UIView *)view
{
for (UIView *subview in view.subviews) {
if ((CGRectGetMinY(subview.frame) == CGRectGetMaxY(self.searchDisplayController.searchBar.frame)) && subview.hidden) {
subview.hidden = NO;
self.searchDisplayController.searchBar.showsScopeBar = YES;
[self.searchDisplayController.searchBar sizeToFit];
}
[self recurseSubviewsForView:subview];
}
}
This is generally a bad idea. There's a basic check to see that the subview being targeted is the subview containing the scope bar, but that could break any second, might not be backwards compatible, etc.
The real question you have to ask yourself is why do I want the scope bar to always be visible? The way it works now, the scope bar will animate visible when the user taps into the search field and hide itself when the search field no longer has the focus. Even with the "hack" above, the search bar gets the focus as soon as the user taps a scope button. What's the point of showing a search option when search isn't even active? When in doubt, fall back to Apple's suggestions. It will make your life a lot easier in the long run, and probably make your app look and behave better. Apple didn't just add that interaction on a whim. They tested it like crazy. That's why it's so hard to make it work another way. That's why there's special code run when a UISearchBar is the headerView of a UITableView...because it's likely better for the user.
In addition, I see your screenshot targeting iOS 8, but your code snipped shows using a UISearchDisplayController. This paradigm has been deprecated in favor of UISearchController. Please consider updating.
I have a textfield that is on a modally presented viewController that is inside a navigation controller, when i use
- (BOOL) textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
the keyboard hides as expected when i push return, but for some reason the whole view that the textfield is in sort of shrinks to the top left and leaves all the subviews shifted to the left. its a really simple view so im not sure what is going wrong, is there a different way to hide the keyboard that could potentially avoid this problem?
here are some screenshots
ive attached the full code here: http://pastebin.com/PKMXEL4U
Ok wow, weirdest symptoms for such a silly mistake, turns out i forgot to put [super viewWillAppear:animated]; in the viewWillAppear it took me reconstructing the whole class and storyboard in a separate project to find that out >.<
I have a ViewController that is just a textfield, a next button, and a back button. I want the text field to always be editable while having the keyboard always present. I also want to customize the keyboard to be my own, but that will come once I figure this part out.
EDIT: The keyboard in my case will only actually be a keypad with 10 digits and a backspace key
What is the best way to go about this? I've been working around with having a UITextField that works with a custom keyboard view, and then make that the first responder when the view loads, but maybe there are better ways.
Thanks in advance!
To make a UITextField always use the keyboard...
In the viewDidAppear or viewWllAppear function do this...
[self.textField becomeFirstResponder];
This will make the keyboard appear and the textField respond to the input.
To dismiss the keyboard you have to run...
[self.textField resignFirstResponder];
As long as you don't run this it will keep keyboard focus.
In the view controller's viewWillAppear: method you can call becomeFirstResponder on the text field. This will make the keyboard appear automatically when the view controller appears. As long as there is no other way to dismiss the keyboard, that is all you need.
Of course on the iPad there is a button on the keyboard to dismiss it. If you want to stop that button from working then implement the following delegate method:
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
return NO;
}
And in case you want to really have your own keyboard. create a view properly sized and beautified ;).. and put in the textFiled's inputView property.
textField.inputView = your custom keyboard view
Cheers.