So I have a UITextView that I'm using to allow the user to submit some text.
My problem is, I can't seem to figure out how to allow the user to 'Cancel' by tapping away from the UITextView.
Simplifying tuzzolotron's answer: Where the following outlet is properly connected in your xib
IBOutlet UITextView *myTextView; Use this in the view controller:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [[event allTouches] anyObject]; if ([myTextView isFirstResponder] && [touch view] != myTextView) { [myTextView resignFirstResponder]; } [super touchesBegan:touches withEvent:event]; } A tap on the View Controller's View, outside of the Text View, will resign the first responder, closing the keyboard.
Another approach I used a lot when working with UITableViews, Searchbar and keyboard is this, I think you can apply it to text field
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)]; [self.tableView addGestureRecognizer:gestureRecognizer]; gestureRecognizer.cancelsTouchesInView = NO; // this prevents the gesture recognizers to 'block' touches [gestureRecognizer release]; And then, here's the simple callback function
- (void)hideKeyboard { [myTextField resignFirstResponder]; } Hope it helps
self.view.endEditing(true) instead of resignFirstResponder.In my view:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; // pass touches up to viewController [self.nextResponder touchesBegan:touches withEvent:event]; } In my viewcontroller:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [[event allTouches] anyObject]; if (keyboardShown && [touch view] != self.TextView) { [self.TextView resignFirstResponder]; } [super touchesBegan:touches withEvent:event]; } - (void)keyboardWasShown:(NSNotification*)aNotification { keyboardShown = YES; } Here is a better solution that does not depend upon an outlet and is going to work with any number of UITextField objects in your controller.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [[event allTouches] anyObject]; if (![[touch view] isKindOfClass:[UITextField class]]) { [self.view endEditing:YES]; } [super touchesBegan:touches withEvent:event]; } endEditing: indiscriminately, switching between text fields still works, keyboard does stay upoverride func touchesBegan(touches: NSSet, withEvent event: UIEvent) { var touch = event.allTouches()?.anyObject() as UITouch if( textfield.isFirstResponder() && touch.view != textfield) { textfield.resignFirstResponder() NSLog("Resigning first responder since touches began outside") } super.touchesBegan(touches, withEvent: event) } ohhorob's answer worked for me too. Here's the simple swift equivalent.
I wanted a version of this that worked for resigning from any view, without requiring specific outlets for each one.. Here is my solution, which I put into one of my standard container views..
It's using MonoTouch C#, though it should be obvious how to convert it to Objective-C
private void findAndResignFirstResponder(UIView node=null) { if (node == null) { return; } if (node.IsFirstResponder) { node.ResignFirstResponder(); return; } foreach (UIView view in node.Subviews) { findAndResignFirstResponder(node:view); } } private bool haveDrag = false; public override void TouchesEnded(NSSet touches, UIEvent evt) { if (!haveDrag) { UITouch touch = (UITouch)evt.AllTouches.AnyObject; if (!touch.View.CanBecomeFirstResponder) { this.findAndResignFirstResponder(this); Console.WriteLine("resign"); } } base.TouchesEnded (touches, evt); } public override void TouchesMoved(NSSet touches, UIEvent evt) { haveDrag = true; base.TouchesMoved (touches, evt); } public override void TouchesBegan(NSSet touches, UIEvent evt) { haveDrag = false; base.TouchesBegan (touches, evt); } My way to do it...
Add a reference to the TextView in the @interface of your ViewController:
@property (weak, nonatomic) IBOutlet UITextView *yourTextView; Override this method in the @implementation of your ViewController:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { if ([self.yourTextView isFirstResponder]) { [self.yourTextView resignFirstResponder]; } }