I have a UITextView in my Navbar that is acting as a search box. I would like to dismiss the associated keyboard when the user taps below the text box - namely on the MKMapView. However I can't figure out how to do this since it doesn't look like I can intercept touches from the mapview.
I have looked at a number of solutions, but none seem to work for my case as far as I can tell. Does anyone have a simple way to do this? I am a bit of a noob, so please let me know if I am not providing some relevant information, and please provide a few lines of example code in your answer if you can - I am still a bit shaky with terminology. Thanks!
screenshot http://img532.imageshack.us/img532/4070/keyboardsm.png
A less hacky solution is to rely on one of the MKMapView delegate methods to dismiss the keyboard
- (void) mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
if ([self.textField isFirstResponder]) {
[self.textField resignFirstResponder];
}
}
Assuming
UITextView *textView;
Then you can dismiss the keyBoard by sending:
[textView resignFirstResponder];
Also: you may prefer to use a UISearchBar and set it as the navigationItem.titleViewof the ViewController. This offers some nice delegate methods.
I know this is an old one but in case anyone else is looks for a simple answer to this, here's my solution to get a "mapView" to resignFirstResponder. This will work in a similar way to the Google Maps app on the iphone, where a semi transparent box appears when you start editing the search text field.
Firstly you need to make your view controller a UISearchBarDelegate
#interface ViewControllerName <UISearchBarDelegate>
// your code here
#end
Then implement the following delegate methods:
#implementation ViewControllerName
// your code here
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
darkBg = [[UIControl alloc] initWithFrame:CGRectMake(0, 244, 320, 300)];
[darkBg setBackgroundColor:[UIColor blackColor]];
[darkBg addTarget:nil action:#selector(hideKeyboard) forControlEvents:UIControlEventTouchDown];
[darkBg setAlpha:0.8];
[UIView beginAnimations:#"slideup" context:nil];
[darkBg setCenter:CGPointMake(160, 194)];
[self.view addSubview:darkBg];
[UIView commitAnimations];
}
- (void)hideKeyboard {
[UIView beginAnimations:#"fadeou" context:nil];
[darkBg setAlpha:0.0];
[UIView commitAnimations];
[addressField resignFirstResponder];
[darkBg performSelector:#selector(removeFromSuperview) withObject:nil afterDelay:1.0];
[darkBg release];
}
Related
i have a screen having navigation controller and text field. when i move next and come back i want the keyboard should be hidden in first screen. I am hiding keyboard like on textfield event.
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
But how to do that in View related events so that whenever my view appears keyboard is hidden..
Pls guide/Help.
thanks in adv.
I think this is also a good way to remove keyboard with in iOS App if your UITextView or UITextField not connected through the IBOutlet.
If you want to Hide Keyboard with UIViewController LifeCycle Events like with viewWillAppear or etc. Follow this
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[self view] endEditing:YES];
}
Otherwise if you object connected using IBOutLet this code will work fine as you describe too.
[yourTextField resignFirstResponder];
Add this code to your ViewWillAppear :
for(id obj in self.view.subviews)
{
if([obj isKindOfClass:[UITextField class]])
{
[obj resignFirstResponder];
}
}
This would take in all the textfields in that particular view here it is the whole view and add the code you had written previously for removing the keyboard.
A good habit is to write this code in your screen's -viewWillDisappear. So, when you navigate from one screen to another at that time it will remove the keyboard from that screen.
- (void)viewWillDisappear:(BOOL)animated
{
[self.view endEditing:YES];
[super viewWillDisappear:animated];
}
For multiple textFields, it is better to use -endEditing for that particular view instead of -resignFirstResponder for any single textField. Take a look at my Answer.
//This is for Swift
override func viewWillAppear(animated: Bool)
{
self.view.endEditing(true)
}
The thing that you are doing wrong is , when you are moving back previous controller to the current controller , the keyboard is up due to the selected textfield of previous controller .
And in the current controller the code:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[self view] endEditing:YES];
}
It will not work as no textfield is selected at this controller. So what you need to do is write the same code in the previous controller viewWillDisappear Method it will surely resolve your Problem .
- (void)viewWillDisappear:(BOOL)animated
{
[self.view endEditing:YES];
[super viewWillDisappear:animated];
}
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 created a webview to display the pdf, now using the gesture recognizer on single tap I have to call some method but single tap is not recognising
I have used this code
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 450,450)];
UITapGestureRecognizer *DoubleFingerDTap = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(screenTappedtwice:)];
DoubleFingerDTap.numberOfTapsRequired = 1;
[webView addGestureRecognizer:DoubleFingerDTap];
[DoubleFingerDTap release];
method called
- (void)screenTappedtwice:(UIGestureRecognizer *)sender {
CGPoint tapPoint = [sender locationInView:sender.view.superview];
[UIView beginAnimations:nil context:NULL];
sender.view.center = tapPoint;
//Check the current state of the navigation bar...
//BOOL navBarState = [self.navigationController isNavigationBarHidden];
// Set the navigationBarHidden to the opposite of the current state.
// [self.navigationController setNavigationBarHidden:TRUE animated:YES];
[self.navigationController setNavigationBarHidden:YES animated:YES];
[UIView commitAnimations];
}
Have you tried setting:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
to return YES? Also, ensure you set your tap gesture's delegate to self so that the message is properly received. I just tested this in a new project and it does work.
EDIT
Not quite sure what your animation begin & commit is for - the method setNavigationBarHidden:animated: animates itself. Additionally, the use of these animation definitions are discouraged in iOS 4 onwards - look into using block-based animations on UIView instead.
For your navigation controller, you are pretty much there - implement something like this:
- (void)screenTappedTwice:(UITapGestureRecognizer *)sender
{
BOOL shouldHideNavBar = [self.navigationController isNavigationBarHidden] ? NO : YES;
[self.navigationController setNavigationBarHidden:shouldHideNavBar animated:YES];
}
In an iPhone app I have a UITextView and a button, which lets the user send the content of the UITextView as a text message. The code looks like this:
MFMessageComposeViewController *picker = [[MFMessageComposeViewController alloc] init];
picker.messageComposeDelegate = self;
picker.body = textView.text;
[self presentModalViewController:picker animated:YES];
Everything works fine, except for when the message is either sent or Cancel is tapped in the MFMessageComposer: The keyboard for the UITextView is not shown anymore, even though the cursor blinks.
I tried a few things, including a [textView resignFirstRepsonder] in both the button code and -viewDidDisappear. [textView becomeFirstResponder] in the MFMessageComposeViewControllerDelegate method or the -viewDidAppear didn't change anything either...
Any ideas?
I had the same issue, and was resigned to accepting fabian's solution, but found that by calling [self dismissModalViewControllerAnimated:NO] and then calling [textView becomeFirstResponder], I was able to make the keyboard reappear. Something about the animation was screwing up the keyboard; looks like a bug in iOS 4.2.
After the view has disappeared, you need to make your view first responder. Add the MFMessageComposeViewControllerDelegate protocol to your header, then use the following:
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result{
[self dismissModalViewControllerAnimated:YES];
[self becomeFirstResponder];
}
Happy coding,
Zane
I had a similar problem and was able to fix it by calling becomeFirstResponder after a slight delay:
[textField performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.01];
The delay trick also solves the problem of missing text cursor after showing an UIAlert right after MFMessageComposeViewController finishes, however the delay needs to be much longer (0.5 sec in my case)
I was not able to find a better solution, so here is my fix:
In
- (void) actionSheet:(UIActionSheet *)actionSheet
willDismissWithButtonIndex:(NSInteger)buttonIndex
I dismiss the Keyboard and in
- (void) actionSheet:(UIActionSheet *)actionSheet
didDismissWithButtonIndex:(NSInteger)buttonIndex`
I present the MFMessageComposeViewController.
In
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller
didFinishWithResult:(MessageComposeResult)result
I don't do [textView becomeFirstResponder] as it doesn't work. Neither does it work in viewDidAppear:. The user has to tap the UITextField again.
Not a very nice solution but the only one I found...
As of iOS 5, here is one workaround. Before you present the MFMessageComposeViewController instance, resign first responder on your UITextView:
[self presentViewController:messageComposer animated:YES completion:NULL];
[textView resignFirstResponder];
Then in the delegate method messageComposeViewController:didFinishWithResult: do this:
[controller dismissViewControllerAnimated:YES completion:^{
[textView performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0];
}];
This fixed the disappearing keyboard problem for me. Without having to permanently dismiss the keyboard.
This behaviour will not appear if viewController which is shown before modal VC is a child of navigation controller. So solution is to make fake UINavigationController and add your VC controller to nav controller.
I am looking for a way to automatically localize texts on buttons/textfields etc and for this method I need to find all (for example) UIButton's on a UIView.
I tried the following 2 methods, but they both do no work like I want them to work:
for (UIView* subView in self.view.subviews)
{
NSLog(#"object class : %#", [subView class]);
if ([subView isMemberOfClass:[UIButton class]])
NSLog(#"Button found!");
}
The problem with this piece of code is that a RoundedRectButton does not match the UIButton class, while it really is just a UIButton.
I also tried the following:
for (UIButton* button in self.view.subviews)
{
// Do my stuff
}
But the stupid thing is, is that cocoa-touch actually just lists all subviews in that for-loop (also the UITextFields etc).
Is there a way to actually just get all UIButtons from a view? Or do I really need to find controls by looking at their selectors.
Why write one-off code like this when you can dial up the awesomeness by adding a category method to UIView using blocks? Take a look at the code at the very bottom. Using this recursive method with blocks you can do things like disable all UITextFields in a view controller's view:
[self.view forEachUITextFieldDoBlock:^(UITextField *textField) {
textfield.enabled = NO;
}];
Or fade out all UITextFields in a view controller's view:
[UIView animateWithDuration:0.25 animations:^{
[self.view forEachUITextFieldDoBlock:^(UITextField *textField) {
textField.alpha = 0.0;
}];
}
completion:^(BOOL finished){
// nothing to do for now
}];
Blocks are pretty amazing in that you can even pass other methods inside a block. For example, the code below passes each UITextField found to my inserAdornmentImage:forTextView method, which adds a custom background image to each text view:
[self.view forEachUITextFieldDoBlock:^(UITextField *textField) {
[self insertAdornmentImage:textFieldBGImage forTextField:textField];
}];
Blocks make the method incredibly flexible so you aren't having to write a specialized method each time you want to do something new with the controls you find. Here's the magic sauce:
#implementation UIView (Helper)
- (void) forEachUITextFieldDoBlock:(void (^)(UITextField *textField))block
{
for (UIView *subview in self.subviews)
{
if ([subview isKindOfClass:[UITextField class]])
{
block((UITextField *)subview);
} else {
[subview forEachUITextFieldDoBlock:block];
}
}
}
#end
the first method is correct, except you need to change isMemberOfClass function to isKindOfClass:
isKindOfClass: Returns a Boolean value
that indicates whether the receiver is
an instance of given class or an
instance of any class that inherits
from that class.