I am trying to recreate something similar to the popup keyboard used in safari.
I am able to visually reproduce it by placeing a toolbar over my view and the appropriate buttons, however i cant figure out any way to dismiss the keyboard once the user has touched the done button.
There is a couple of things you need to remember. The number #1 part developers forget to set is the delegate of the textField.
If you are using the Interface Builder, you must remember that you need to set the delegate of the textField to the file Owner.
If you are not using Interface Builder then make sure you set the delegate of the textfield to self. I also include the returnType. For Example if the textField was called gameField:
gameField.delegate = self;
gameField.returnKeyType = UIReturnKeyDone;
You must also implement the UITextFieldDelegate for your ViewController.
#interface YourViewController : UIViewController <UITextFieldDelegate>
Finally you need to use the textFieldShouldReturn method and call [textField resignFirstResponder]
-(BOOL) textFieldShouldReturn:(UITextField*) textField {
[textField resignFirstResponder];
return YES;
}
All your textFields will use this same method so you only need to have this setup once. As long as the delegate is set for the textField, the UITextFieldDelegate is implemented for the interface, you add the textFieldShouldReturn method and call the
resignFirstResponder your set.
Have you tried:
[viewReceivingKeys resignFirstResponder];
where viewReceivingKeys is the UIView that is receiving the text input?
If your building your own views in Interface Builder, set your view controller to be delegate for the text field and implement textFieldShouldReturn: from UITextFieldDelegate in your views controller.
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField
{
NSLog(#"%# textFieldShouldReturn", [self class]);
[theTextField resignFirstResponder];
// do stuff with the text
NSLog(#"text = %#", [theTextField text]);
return YES;
}
UITextFieldDelegate textFieldShouldReturn: in the iphone cocoa docs
If you're talking about dismissing the keyboard from a UITextField rather than a UITextView. Your question isn't that clear? If you are then ensure your class is marked as a UITextFieldDelegate in the interface file,
#interface MyController: UIViewController <UITextFieldDelegate> {
UITextField *activeTextField;
// ...remainder of code not show ...
}
and then you should implement the two delegate methods as below,
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
activeTextField = textField;!
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
activeTextField = nil;
[textField resignFirstResponder];
return YES;
}
However if you're using a UITextView then things are a bit more complicated. The UITextViewDelegate protocol lacks the equivalent to the textFieldShouldReturn: method, presumably since we shouldn’t expect the Return key to be a signal that the user wishes to stop editing the text in a multi-line text entry dialog (after all, the user may want to insert line breaks by pressing Return).
However, there are several ways around the inability of the UITextView to resign as first responder using the keyboard. The usual method is to place a Done button in the navigation bar when the UITextView presents the pop-up keyboard. When tapped, this button asks the text view to resign as first responder, which will then dismiss the keyboard.
However, depending on how you’ve planned out your interface, you might want the UITextView to resign when the user taps outside the UITextView itself. To do this, you’d subclass UIView to accept touches, and then instruct the text view to resign when the user taps outside the view itself.
Create a new class,
#import <UIKit/UIKit.h>
#interface CustomView : UIView {
IBOutlet UITextView *textView;
}
#end
Then, in the implementation, implement the touchesEnded:withEvent: method and ask the UITextView to resign as first responder.
#import "CustomView.h"
#implementation CustomView
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
}
return self;
}
- (void) awakeFromNib {
self.multipleTouchEnabled = YES;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"touches began count %d, %#", [touches count], touches);
[textView resignFirstResponder];
[self.nextResponder touchesEnded:touches withEvent:event];
}
#end
Once you’ve added the class, you need to save all your changes, then go into Interface Builder and click on your view. Open the Identity inspector in the Utility pabel and change the type of the view in your nib file to be your CustomView rather than the default UIView class. Then in the Connections Inspector, drag the textView outlet to the UITextView. After doing so, and once you rebuild your application, touches outside the active UI elements will now dismiss the keyboard. Note however that if the UIView you are subclassing is “behind” other UI elements, these elements will intercept the touches before they reach the UIView layer. So while this solution is elegant, it can be used in only some situations. In many cases, you’ll have to resort to the brute force method of adding a Done button to the navigation bar to dismiss the keyboard.
use a navigation controller and pop the view when done?
for example, I use code like this to slide an about box in:
[[self navigationController] presentModalViewController:modalViewController animated:YES];
and then when the button in that about box is clicked, I use this to get rid of it:
[self.navigationController dismissModalViewControllerAnimated:YES];
In my case the about box occupies the whole screen, but I don't think it would have to for this to work.
edit: I think I may have misunderstood your question. Something along the lines of my code would be if you are faking the whole keyboard view yourself. I think that resign first responder is the right way to do it if it is the normal keyboard with your toolbar added on top.
Related
I have a app I'm making that has 2 text fields and buttons below it. When the user starts to type, the keyboard comes up and covers the buttons. Is there a way to make the keyboard go away?
There are two ways to do so
// this one line will dismiss the keyboard from anywhere in your code
[self.view endEditing:YES];
or
with the delegate of textfield (you should declare it in your .h file first)
#interface someController : UIViewController <UITextFieldDelegate>
and the in .m
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
// next line will dismiss the keyboard
[textField resignFirstResponder];
return YES;
}
Check UITextField documentation:
To dismiss the keyboard, send the resignFirstResponder message to the text field that is currently the first responder. Doing so causes the text field object to end the current editing session (with the delegate object’s consent) and hide the keyboard.
In other words, just send resignFirstResponder to an active text field object.
I use this:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
[self.alertView dismissWithClickedButtonIndex:self.alertView.firstOtherButtonIndex animated:YES];
return YES;
}
In the view controller after setting the text field delegate to self.
I have a button and a textfield. I just want keyboard disappear when clicking on button. Why my code below doesn't work.
Update: I saw something about file owner. I don't understand how to do this in XCode4 I use storyboard and I can't see any file owner icon.
Update 2: I found a tut http://www.techotopia.com/index.php/Writing_iOS_4_Code_to_Hide_the_iPhone_Keyboard_%28Xcode_4%29 but it uses XIB file on XCode 4 not storyboard. How to do this with storyboard ?
myViewController.h
#interface myViewController : UIViewController <UITextFieldDelegate>
{
UITextField *myTextField;
}
#property (retain, nonatomic) IBOutlet UITextField *myTextField;
myViewController.m
- (BOOL)textFieldShouldReturn: (UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
- (void)viewDidLoad
{
[super viewDidLoad];
myTextField.delegate = self;
}
- (IBAction)DoCalc:(id)sender {
// ...
}
Check to see if the textFieldShouldReturn function that you've written into myViewController.m is even being called. Set a breakpoint inside of it and then run the simulator. Press the return key on the keyboard. If the program doesn't break, then the function you've written isn't being called.
If it is, it's because you haven't delegated UIResponder duties to your view controller. Make sure you are delegating responder duties to your myViewController class for the UITextField that you're working with.
In storyboard, you do this by control-dragging from the UITextField widget to the yellow orb below the scene, and selecting "delegate" from the context menu that appears.
textFieldShouldReturn: should return NO to hide the keyboard. One more thing - do not set first responder to self, [textField resignFirstResponder] is enough, iOS should figure nextResponder by itself.
You can hide the keybord in this method...
- (void)textFieldDidEndEditing:(UITextField *)textField {
[textField resignFirstResponder];
}
Remove [self becomeFirstResponder]; should do it.
resignFirstResponder is to dismiss the keyboard. while becomeFirstResponder is to open the keyboard. so in your code, you are closing then opening again the keyboard at the same time. The last action is opened the keyboard, hence it won't close.
you may look into UIResponder Class as superclass of UITextField
I'm trying to hide the number pad, but I do not want to implement a button.
Is there a way to dismiss the number pad when the user taps outside the textfield?
This is one of those questions where you read it and say "That's easy you just..". And then you go to do it and make it super complicated. And then realize it doesn't have to be that complicated.
The answer I've come up with, and I'm sure it will help someone else, Is to use an invisible UIView that never interacts but acts on other views and maybe not in the way you'd think.
The typical answer to a question about dismissing the UIKeyboardTypeNumberPad keyboard is to add a bar that has a button as the inputAccessoryView to dismiss the keyboard. If a bar and button are undesirable generally you just listen for touch events on the background and your good to go but this question is about a tableview and that makes this much harder.
But this inputAccessoryView feature is still awesome. It allows you to define a UIView or UIView subclass to be displayed when the keyboard is shown. More importantly when the keyboard is shown due to a textfield for which it is the inputAccessoryView becoming first responder.
I could yammer on but first here is some code for a lightweight class that actually performs very well in testing.
The contents of NJ_KeyboardDismisser.h are:
#import <UIKit/UIKit.h>
// For some reason neither inputView or inputAccessoryView are IBOutlets, so we cheat.
#interface UITextField (WhyDoIHaveToDoThisApple)
#property (readwrite, retain) IBOutlet UIView *inputAccessoryView;
#end
#interface NJ_KeyboardDismisser : UIView
#property (nonatomic, weak) IBOutlet UIView *mainView;
-(id)initWithMainView:(UIView *)view; // convienience method for code
#end
And the contents of NJ_KeyboardDismisser.m are:
#import "NJ_KeyboardDismisser.h"
#implementation NJ_KeyboardDismisser {
UITapGestureRecognizer *_tapGR;
}
#synthesize mainView = _mainView;
-(void)setMainView:(UIView *)view{
if (_tapGR) [_tapGR.view removeGestureRecognizer:_tapGR];
_mainView = view;
_tapGR = [[UITapGestureRecognizer alloc] initWithTarget:_mainView action:#selector(endEditing:)];
}
-(id)initWithMainView:(UIView *)view{
if ((self = [super initWithFrame:CGRectMake(0, 0, 0, 0)])){
self.mainView = view;
}
return self;
}
-(void)didMoveToWindow{ // When the accessory view presents this delegate method will be called
[super didMoveToWindow];
if (self.window){ // If there is a window one of the textfields, for which this view is inputAccessoryView, is first responder.
[self.mainView addGestureRecognizer:_tapGR];
}
else { // If there is no window the textfield is no longer first responder
[self.mainView removeGestureRecognizer:_tapGR];
}
}
#end
You may recognize the endEditing: method, as mentioned by Cosique, it is a UIView extension method that asks a views nested textfield to resign. Sound handy? It is. By calling it on the tableview the textfield it contains resigns first responder. Since this technique works on all UIViews there is no need to artificially limit this outlet to only UITableViews so the outlet is just UIView *mainView.
The final moving part here is the UITapGestureRecognizer. We don't want to add this recognizer full time for fear of screwing up the tableview's workings. So we take advantage of UIView's delegate method didMoveToWindow. We don't really do anything with the window we just check to see if we are in one; If we are then one of our textfields is first responder, if not then it's not. We add and remove our gesture recognizer accordingly.
Okay straightforward enough, but how do you use it? Well if instantiating in code you could do it like this, in tableView:cellForRowAtIndexPath::
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
UITextField *field = [[UITextField alloc] initWithFrame:CGRectMake(20, 6, 100, 31)];
[cell.contentView addSubview:field];
field.keyboardType = UIKeyboardTypeNumberPad;
field.inputAccessoryView = [[NJ_KeyboardDismisser alloc] initWithMainView:self.view];
}
If you are using static cells in a storyboard then the technique is different (obviously). First drag out a generic NSObject and place it in the dark grey strip below the view (where the other objects such as the view controller are). Then change this new object's class to be NJ_KeyboardDismisser. Then connect the "Keyboard Dismisser"'s mainView property to that view (generally a tableview). Then connect the inputAccessoryView property from any each text field in that scene you wish to the "Keyboard Dismisser".
Give it a try! The tableview acts normally. Apple's tap recognizer is smart enough to ignore the swipes on the table, so you can scroll. It also ignores touches in the textfields so you can edit and select other textfields. But tap outside a textfield and the keyboard is gone.
Note: This class's use is not limited to tableviews. If you want to use it on a regular view, just set the mainView property to be the same as the view controller's view.
The easiest way is to do this in your view controller:
[self.view endEditing: YES];
You can resign the responder inside the below function for your view:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
Make sure your view is enabled for user interaction.
when creating the text field add a tag to it.
like this Yourtextfield.tag = 1;
and in you touchesEnded method
do this :
UITextField *resignTextField = (UITextField *)[self.view viewWithTag:1];
[resignTextField resignFirstResponder];
I have a editable text box and when I click on it I get a keyboard. But, it won't let me close out of the keyboard. When I go into the properties of the editable text object ( the Text View object ) and make the return button "Done" it still won't let me exit out.
You should do it programatically, by using resignFirstResponder message on the UITextField is currently being edited with the keyboard. Check this Stack Overflow question on the issue.
First, you need to make sure you controller is a UITextField Delegate in your .h- something like this:
#interface UserAddEditController : UIViewController <UITextFieldDelegate>
2nd, you need to implement the following:
- (BOOL)textFieldShouldReturn:(UITextField *) theTextField {
[theTextField resignFirstResponder];
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
[textField resignFirstResponder];
}
Finally, make sure your UITextField's delegate is set to your File Owner in interface builder.
That should do it!
Does anyone know how to cancel (resign First Responder) out of a UISearchBar when you tap below the search text box and above the keyboard? Can anyone help post some code to handle this?
Thanks
Add a tap gesture in the parent view (of the UISearchbar)
[self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:searchBar action:#selector(resignFirstResponder)]];
I accomplished this by using a UITapGestureRecognizer:
UIGestureRecognizer* cancelGesture;
- (void) backgroundTouched:(id)sender {
[self.view endEditing:YES];
}
#pragma mark - UISearchBarDelegate
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
cancelGesture = [UITapGestureRecognizer new];
[cancelGesture addTarget:self action:#selector(backgroundTouched:)];
[self.view addGestureRecognizer:cancelGesture];
}
-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
if (cancelGesture) {
[self.view removeGestureRecognizer:cancelGesture];
[cancelGesture release];
cancelGesture = nil;
}
}
The code is a bare, but you can see the intent. When the SearchBar starts editing, you attach a tap gesture recognizer to the view controller's view, and remove it when it stops editing.
There are a couple caveats that you can work around: doing this will make it so if you click anything besides the keyboard or the search bar's text field, the recognizer traps the click -- so if you use the clear, cancel, scope or results button they won't respond correctly.
In my particular scenario, I had a UITableView that was covering the exposed area of the view so I attached the gesture recognizer to it instead of the view controllers main view, isolating the area to which the gesture would respond.
An alternative idea I got from iphonedevbook, sample code project 04, was to use one big transparent button that lies behind all other controls which does nothing but resign all first responders if tapped. I.e. if the user taps anywhere where there isn't a more important control - which is the intuitive behavior - the search bar and keyboard disappear.
I ended up using a hybrid of Hauke's and Beau Scott's approach. There were two problems I ran into using their solutions:
1) If there's anything else on the screen, tapping it won't result in resignFirstResponder being called. For example, if the user taps a button rather than the space around the button, the button will eat the event. Beau Scott's solution addresses this issue, however.
2) Tapping the search bar itself will result in resignFirstResponder getting called. Clearly you don't want the keyboard to disappear when you tap UISearchBar. A small change described below addresses this.
I ended up setting up my view as follows. The parent view has two children - the UISearchBar and a subview which holds the rest of my UI elements. The subview takes up the entire screen below the UISearchBar. Then I used Beau Scott's exact code to add and remove the gesture recognizer, but instead of adding it to self.view I added it to the subview:
IBOutlet UIView *gestureRecognizer;
...
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
cancelGesture = [UITapGestureRecognizer new];
[cancelGesture addTarget:self action:#selector(backgroundTouch:)];
[gestureRecognizer addGestureRecognizer:cancelGesture];
}
-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
if (cancelGesture) {
[gestureRecognizer removeGestureRecognizer:cancelGesture];
[cancelGesture release];
cancelGesture = nil;
}
}
First, you need a reference to the search bar. Let's assume that your controller object has an object reference UISearchBar *theSearchBar, and that you assign it when you create the UISearchBar object.
Next, you need to detect that the containing view has been touched. The view that is touched "knows", but you need get that information to the controller. Sadly, Apple didn't provide a simple way to do this, but it's not that hard either.
My solution is to replace the standard UIView that a UIViewController object normally creates with a UIControl, and then make the UIViewController respond to touch events.
MainController.m
- (void) loadView {
UIControl *control = [[UIControl alloc] initWithFrame: <desired frame>];
[control addTarget: self action: #selector(touchUpInside)
forControlEvents: UIControlEventTouchUpInside];
// or touch down events, or whatever you like
self.view = control;
[control release];
}
- (void) viewDidLoad {
[super viewDidLoad];
theSearchBar = [[UISearchBar alloc] initWithFrame: <desired frame>];
// insert code to finish customizing the search bar
[self.view addSubview: theSearchBar];
}
- (void) touchUpInside {
if [theSearchBar isFirstResponder] {
// grab any data you need from the search bar
[theSearchBar resignFirstResponder];
}
}
MainController.h
#interface MainController : UIViewController
{
UISearchBar *theSearchBar;
}
Clarification:
There is only a single object -- let's call the class MainController -- which is a subclass of UIViewController. All of the methods listed above are implemented in MainController. theSearchBar is declared as a UISearchBar* in the .h file.
Are you defining your view and controller using Interface Builder? If so, I suggest you learn how to NOT use it -- once you get into the kind of tricks we are discussing here, it becomes more of a hindrance than a help -- I don't use it at all, ever.
#Gia Dang's answer is the simplest, but I don't subclass the UIView, only the UIViewController, so my call is slightly different. Also, since I don't know the overhead for actually calling resignFirstResponder, I prefer to check first. It's more code, but since all of this is done on the main thread (which can slow down the UI), I'd rather check first.
#implementation MyController : UIViewController {
#private
UISearchController *_uiSearchController;
}
- (void)viewDidLoad {
// add tap on view to resign the responder if we're in the middle of typing in the search
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(closeKeyboardIfNeeded)];
[self.view addGestureRecognizer:tapGestureRecognizer];
}
- (void)closeKeyboardIfNeeded {
if (![_uiSearchController.searchBar isFirstResponder]) {
return;
}
[_uiSearchController.searchBar resignFirstResponder];
}
#end
As for the other answers, be careful about constantly recreating objects. There is always a performance hit, whether it's the creation itself or the garbage collection through ARC, and these things will slow down your main thread. Depending on what you're doing also on the main thread, it may have a significant performance impact.