6

(my boss says) that I have to implement a "Done" button on a navBar so that the various items in the view (that contain an edit box) will dismiss their keyboard (if they were in focus).

It seems that I must iterate through all items and then call resignFirstResponder on each on the off-chance that one of them is in focus? This seems a bit messy (and hard to maintain if e.g. someone else adds more items in future) - is there a better way to do it?

Robin Pain
  • 639
  • 2
  • 8
  • 17

4 Answers4

16

I have found it!

Thanks to this

I discovered that all I need do is this:-

-(void) done {
    [[self.tableView superview] endEditing:YES];
}

// also [self.view endEditing:YES]; works fine

[remark] Also I learn how to do the equivalent of an "eventFilter" to stop UITableViewController from swallowing background touch events by intercepting them before they get there - from the same, wonderful post on that thread - see "DismissableUITableView". [end of remark]

Community
  • 1
  • 1
Robin Pain
  • 639
  • 2
  • 8
  • 17
  • 4
    A minor gotcha here, the BOOL argument for `-endEditing:` actually determines whether or not the view will be forced to resign first responder status. Forcing this on a view means that `-canResignFirstResponder` will not be sent to the view. Use `[self.view endEditing:NO];` for the normal behavior. – Mark Adams Nov 24 '11 at 05:01
0

I think best way to handle it by searching all subviews of main view with recursive function, check example below

- (BOOL)findAndResignFirstResponder {
if (self.isFirstResponder) {
    [self resignFirstResponder];
    return YES;
}

    for (UIView *subView in self.subviews) {
        if ([subView findAndResignFirstResponder]) {
            return YES;
        }
    }
    return NO;
}

and also you can put this method to your utility class and can use from tap gesture. All you have to do is simply adding to gesture to view.

UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(hideEverything)];
[self.tableView addGestureRecognizer:gestureRecognizer];

and than you can call hideEverything method;

- (void) hideKeyboard {
    [self.view findAndResignFirstResponder];
    ...
    ...
}
mert
  • 1,090
  • 13
  • 26
0

You don't have to iterate through the controls since only one can be first responder at the moment.

This will reset the responder to the Window itself: [[self window] makeFirstResponder:nil]

Gobra
  • 4,263
  • 2
  • 15
  • 20
  • Thanks Gobra. I get an "unrecognized selector..." error - this object is a UITableViewController and that inherits from UIResponder and neither have that window() method? – Robin Pain Sep 03 '10 at 12:50
  • I have suggested solution for MacOS, not iOS (tags). I'm not sure whether UI-classes have similar method. – Gobra Sep 03 '10 at 13:13
0

One solution is to use a currentTextField Object,

In .h file have an instance variable as

UITextField *currentTextField;

Now in .m file.

Note : Dont forget to set the delegates of all the textField to this class

- (void)textViewDidBeginEditing:(UITextView *)textView
{
   currentTextField = textField;
}

- (void)textViewDidEndEditing:(UITextView *)textView
{
   currentTextField = nil;
}

Now in your button action method

-(IBAction)buttonTap
{
    if([currentTextField isFirstResponder])
        [currentTextField resignFirstResponder];
}

This avoids iterating through all the text field.

RVN
  • 4,157
  • 5
  • 32
  • 35